├── .gitignore
├── LICENSE
├── README.md
├── Swifty-OCR-Translator.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcuserdata
│ └── pangmo5.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
└── Swifty-OCR-Translator
├── APIs
└── GoogleTranslateAPI.swift
├── Assets.xcassets
├── AccentColor.colorset
│ └── Contents.json
├── AppIcon.appiconset
│ ├── Contents.json
│ ├── icon-1024.png
│ ├── icon-128.png
│ ├── icon-16.png
│ ├── icon-256.png
│ ├── icon-257.png
│ ├── icon-32.png
│ ├── icon-33.png
│ ├── icon-512.png
│ ├── icon-513.png
│ └── icon-64.png
└── Contents.json
├── Enums
├── Language.swift
└── Translator.swift
├── Extensions
└── Defaults++.swift
├── Info.plist
├── Models
├── APIInfo.swift
└── GoogleTranslateModels.swift
├── Preview Content
└── Preview Assets.xcassets
│ └── Contents.json
├── Swifty_OCR_Translator.entitlements
├── Swifty_OCR_TranslatorApp.swift
├── ViewModels
├── MainViewModel.swift
└── MenuViewModel.swift
└── Views
├── MainView.swift
└── MenuView.swift
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/swift,swiftpackagemanager,macos,xcode
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=swift,swiftpackagemanager,macos,xcode
4 |
5 | ### macOS ###
6 | # General
7 | .DS_Store
8 | .AppleDouble
9 | .LSOverride
10 |
11 | # Icon must end with two \r
12 | Icon
13 |
14 |
15 | # Thumbnails
16 | ._*
17 |
18 | # Files that might appear in the root of a volume
19 | .DocumentRevisions-V100
20 | .fseventsd
21 | .Spotlight-V100
22 | .TemporaryItems
23 | .Trashes
24 | .VolumeIcon.icns
25 | .com.apple.timemachine.donotpresent
26 |
27 | # Directories potentially created on remote AFP share
28 | .AppleDB
29 | .AppleDesktop
30 | Network Trash Folder
31 | Temporary Items
32 | .apdisk
33 |
34 | ### Swift ###
35 | # Xcode
36 | #
37 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
38 |
39 | ## User settings
40 | xcuserdata/
41 |
42 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
43 | *.xcscmblueprint
44 | *.xccheckout
45 |
46 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
47 | build/
48 | DerivedData/
49 | *.moved-aside
50 | *.pbxuser
51 | !default.pbxuser
52 | *.mode1v3
53 | !default.mode1v3
54 | *.mode2v3
55 | !default.mode2v3
56 | *.perspectivev3
57 | !default.perspectivev3
58 |
59 | ## Obj-C/Swift specific
60 | *.hmap
61 |
62 | ## App packaging
63 | *.ipa
64 | *.dSYM.zip
65 | *.dSYM
66 |
67 | ## Playgrounds
68 | timeline.xctimeline
69 | playground.xcworkspace
70 |
71 | # Swift Package Manager
72 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
73 | # Packages/
74 | # Package.pins
75 | # Package.resolved
76 | # *.xcodeproj
77 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
78 | # hence it is not needed unless you have added a package configuration file to your project
79 | # .swiftpm
80 |
81 | .build/
82 |
83 | # CocoaPods
84 | # We recommend against adding the Pods directory to your .gitignore. However
85 | # you should judge for yourself, the pros and cons are mentioned at:
86 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
87 | # Pods/
88 | # Add this line if you want to avoid checking in source code from the Xcode workspace
89 | # *.xcworkspace
90 |
91 | # Carthage
92 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
93 | # Carthage/Checkouts
94 |
95 | Carthage/Build/
96 |
97 | # Accio dependency management
98 | Dependencies/
99 | .accio/
100 |
101 | # fastlane
102 | # It is recommended to not store the screenshots in the git repo.
103 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
104 | # For more information about the recommended setup visit:
105 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
106 |
107 | fastlane/report.xml
108 | fastlane/Preview.html
109 | fastlane/screenshots/**/*.png
110 | fastlane/test_output
111 |
112 | # Code Injection
113 | # After new code Injection tools there's a generated folder /iOSInjectionProject
114 | # https://github.com/johnno1962/injectionforxcode
115 |
116 | iOSInjectionProject/
117 |
118 | ### SwiftPackageManager ###
119 | Packages
120 | xcuserdata
121 | *.xcodeproj
122 |
123 |
124 | ### Xcode ###
125 | # Xcode
126 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
127 |
128 |
129 |
130 |
131 | ## Gcc Patch
132 | /*.gcno
133 |
134 | ### Xcode Patch ###
135 | *.xcodeproj/*
136 | !*.xcodeproj/project.pbxproj
137 | !*.xcodeproj/xcshareddata/
138 | !*.xcworkspace/contents.xcworkspacedata
139 | **/xcshareddata/WorkspaceSettings.xcsettings
140 |
141 | # End of https://www.toptal.com/developers/gitignore/api/swift,swiftpackagemanager,macos,xcode
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Kwangmin Bae
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [!NOTE]
2 | We're currently building `SwiftyCrow`, a new app that supports cost-free Apple in-device translation and real-time on-screen translation.
3 |
4 | # Swifty-OCR-Translator
5 | Screen translator for macOS with Apple Vision API and IBM Watson, Google Cloud Translator
6 |
7 | ## Usage
8 | 1. Select Translator
9 | 2. Fill in the API fields for each translator. ([IBM](https://cloud.ibm.com/docs/language-translator?topic=language-translator-gettingstarted#prerequisites), [Google](https://cloud.google.com/translate/docs/setup))
10 | 3. Select Source and Target languages
11 | 4. Press [⌘ + ⇧ + 1]
12 | 5. Drag the area with the text you want to translate.
13 |
14 | https://user-images.githubusercontent.com/16532526/125570720-31671575-c025-4368-8aa6-2c0dab9c78d3.mov
15 |
16 | ## Credits
17 | ### App Icon
18 | - 화라낙현
19 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 6275308226945D4900F0524C /* Swifty_OCR_TranslatorApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6275308126945D4900F0524C /* Swifty_OCR_TranslatorApp.swift */; };
11 | 6275308426945D4900F0524C /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6275308326945D4900F0524C /* MainView.swift */; };
12 | 6275308626945D4A00F0524C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6275308526945D4A00F0524C /* Assets.xcassets */; };
13 | 6275308926945D4A00F0524C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6275308826945D4A00F0524C /* Preview Assets.xcassets */; };
14 | 62B0A6E9269803C500099685 /* Magnet in Frameworks */ = {isa = PBXBuildFile; productRef = 62B0A6E8269803C500099685 /* Magnet */; };
15 | 62B870132698194E0078BFB2 /* MenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62B870122698194E0078BFB2 /* MenuViewModel.swift */; };
16 | 62B8701626981B0E0078BFB2 /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 62B8701526981B0E0078BFB2 /* Defaults */; };
17 | 62B8701826981DAF0078BFB2 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62B8701726981DAF0078BFB2 /* MenuView.swift */; };
18 | 62B8701B269823910078BFB2 /* Defaults++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62B8701A269823910078BFB2 /* Defaults++.swift */; };
19 | 62B8702726982FC60078BFB2 /* LanguageTranslatorV3 in Frameworks */ = {isa = PBXBuildFile; productRef = 62B8702626982FC60078BFB2 /* LanguageTranslatorV3 */; };
20 | 62C4E5DE2850858700224761 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C4E5DD2850858700224761 /* Language.swift */; };
21 | 62EB5C1B269E839F001DA95A /* Translator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EB5C1A269E839F001DA95A /* Translator.swift */; };
22 | 62EB5C1E269E8421001DA95A /* APIInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EB5C1D269E8421001DA95A /* APIInfo.swift */; };
23 | 62EB5C26269E93A9001DA95A /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 62EB5C25269E93A9001DA95A /* Moya */; };
24 | 62EB5C28269E93C2001DA95A /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 62EB5C27269E93C2001DA95A /* CombineMoya */; };
25 | 62EB5C2A269E93CC001DA95A /* GoogleTranslateAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EB5C29269E93CC001DA95A /* GoogleTranslateAPI.swift */; };
26 | 62EB5C2C269E9626001DA95A /* GoogleTranslateModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EB5C2B269E9626001DA95A /* GoogleTranslateModels.swift */; };
27 | 62EB5C2E269EA616001DA95A /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EB5C2D269EA616001DA95A /* MainViewModel.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXFileReference section */
31 | 6275307E26945D4900F0524C /* Swifty-OCR-Translator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Swifty-OCR-Translator.app"; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 6275308126945D4900F0524C /* Swifty_OCR_TranslatorApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swifty_OCR_TranslatorApp.swift; sourceTree = ""; };
33 | 6275308326945D4900F0524C /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; };
34 | 6275308526945D4A00F0524C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
35 | 6275308826945D4A00F0524C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
36 | 6275308A26945D4A00F0524C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | 6275308B26945D4A00F0524C /* Swifty_OCR_Translator.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Swifty_OCR_Translator.entitlements; sourceTree = ""; };
38 | 62B870122698194E0078BFB2 /* MenuViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewModel.swift; sourceTree = ""; };
39 | 62B8701726981DAF0078BFB2 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; };
40 | 62B8701A269823910078BFB2 /* Defaults++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Defaults++.swift"; sourceTree = ""; };
41 | 62C4E5DD2850858700224761 /* Language.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; };
42 | 62EB5C1A269E839F001DA95A /* Translator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Translator.swift; sourceTree = ""; };
43 | 62EB5C1D269E8421001DA95A /* APIInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIInfo.swift; sourceTree = ""; };
44 | 62EB5C29269E93CC001DA95A /* GoogleTranslateAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleTranslateAPI.swift; sourceTree = ""; };
45 | 62EB5C2B269E9626001DA95A /* GoogleTranslateModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleTranslateModels.swift; sourceTree = ""; };
46 | 62EB5C2D269EA616001DA95A /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = ""; };
47 | /* End PBXFileReference section */
48 |
49 | /* Begin PBXFrameworksBuildPhase section */
50 | 6275307B26945D4900F0524C /* Frameworks */ = {
51 | isa = PBXFrameworksBuildPhase;
52 | buildActionMask = 2147483647;
53 | files = (
54 | 62B8701626981B0E0078BFB2 /* Defaults in Frameworks */,
55 | 62B0A6E9269803C500099685 /* Magnet in Frameworks */,
56 | 62EB5C26269E93A9001DA95A /* Moya in Frameworks */,
57 | 62EB5C28269E93C2001DA95A /* CombineMoya in Frameworks */,
58 | 62B8702726982FC60078BFB2 /* LanguageTranslatorV3 in Frameworks */,
59 | );
60 | runOnlyForDeploymentPostprocessing = 0;
61 | };
62 | /* End PBXFrameworksBuildPhase section */
63 |
64 | /* Begin PBXGroup section */
65 | 6275307526945D4900F0524C = {
66 | isa = PBXGroup;
67 | children = (
68 | 6275308026945D4900F0524C /* Swifty-OCR-Translator */,
69 | 6275307F26945D4900F0524C /* Products */,
70 | 62B8702226982C540078BFB2 /* Frameworks */,
71 | );
72 | sourceTree = "";
73 | };
74 | 6275307F26945D4900F0524C /* Products */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 6275307E26945D4900F0524C /* Swifty-OCR-Translator.app */,
78 | );
79 | name = Products;
80 | sourceTree = "";
81 | };
82 | 6275308026945D4900F0524C /* Swifty-OCR-Translator */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 62EB5C21269E9199001DA95A /* APIs */,
86 | 62EB5C1C269E840B001DA95A /* Models */,
87 | 62EB5C19269E838A001DA95A /* Enums */,
88 | 62B87019269823870078BFB2 /* Extensions */,
89 | 62B87011269819080078BFB2 /* ViewModels */,
90 | 62B87010269818FE0078BFB2 /* Views */,
91 | 6275308126945D4900F0524C /* Swifty_OCR_TranslatorApp.swift */,
92 | 6275308526945D4A00F0524C /* Assets.xcassets */,
93 | 6275308A26945D4A00F0524C /* Info.plist */,
94 | 6275308B26945D4A00F0524C /* Swifty_OCR_Translator.entitlements */,
95 | 6275308726945D4A00F0524C /* Preview Content */,
96 | );
97 | path = "Swifty-OCR-Translator";
98 | sourceTree = "";
99 | };
100 | 6275308726945D4A00F0524C /* Preview Content */ = {
101 | isa = PBXGroup;
102 | children = (
103 | 6275308826945D4A00F0524C /* Preview Assets.xcassets */,
104 | );
105 | path = "Preview Content";
106 | sourceTree = "";
107 | };
108 | 62B87010269818FE0078BFB2 /* Views */ = {
109 | isa = PBXGroup;
110 | children = (
111 | 6275308326945D4900F0524C /* MainView.swift */,
112 | 62B8701726981DAF0078BFB2 /* MenuView.swift */,
113 | );
114 | path = Views;
115 | sourceTree = "";
116 | };
117 | 62B87011269819080078BFB2 /* ViewModels */ = {
118 | isa = PBXGroup;
119 | children = (
120 | 62B870122698194E0078BFB2 /* MenuViewModel.swift */,
121 | 62EB5C2D269EA616001DA95A /* MainViewModel.swift */,
122 | );
123 | path = ViewModels;
124 | sourceTree = "";
125 | };
126 | 62B87019269823870078BFB2 /* Extensions */ = {
127 | isa = PBXGroup;
128 | children = (
129 | 62B8701A269823910078BFB2 /* Defaults++.swift */,
130 | );
131 | path = Extensions;
132 | sourceTree = "";
133 | };
134 | 62B8702226982C540078BFB2 /* Frameworks */ = {
135 | isa = PBXGroup;
136 | children = (
137 | );
138 | name = Frameworks;
139 | sourceTree = "";
140 | };
141 | 62EB5C19269E838A001DA95A /* Enums */ = {
142 | isa = PBXGroup;
143 | children = (
144 | 62EB5C1A269E839F001DA95A /* Translator.swift */,
145 | 62C4E5DD2850858700224761 /* Language.swift */,
146 | );
147 | path = Enums;
148 | sourceTree = "";
149 | };
150 | 62EB5C1C269E840B001DA95A /* Models */ = {
151 | isa = PBXGroup;
152 | children = (
153 | 62EB5C1D269E8421001DA95A /* APIInfo.swift */,
154 | 62EB5C2B269E9626001DA95A /* GoogleTranslateModels.swift */,
155 | );
156 | path = Models;
157 | sourceTree = "";
158 | };
159 | 62EB5C21269E9199001DA95A /* APIs */ = {
160 | isa = PBXGroup;
161 | children = (
162 | 62EB5C29269E93CC001DA95A /* GoogleTranslateAPI.swift */,
163 | );
164 | path = APIs;
165 | sourceTree = "";
166 | };
167 | /* End PBXGroup section */
168 |
169 | /* Begin PBXNativeTarget section */
170 | 6275307D26945D4900F0524C /* Swifty-OCR-Translator */ = {
171 | isa = PBXNativeTarget;
172 | buildConfigurationList = 6275308E26945D4A00F0524C /* Build configuration list for PBXNativeTarget "Swifty-OCR-Translator" */;
173 | buildPhases = (
174 | 6275307A26945D4900F0524C /* Sources */,
175 | 6275307B26945D4900F0524C /* Frameworks */,
176 | 6275307C26945D4900F0524C /* Resources */,
177 | );
178 | buildRules = (
179 | );
180 | dependencies = (
181 | );
182 | name = "Swifty-OCR-Translator";
183 | packageProductDependencies = (
184 | 62B0A6E8269803C500099685 /* Magnet */,
185 | 62B8701526981B0E0078BFB2 /* Defaults */,
186 | 62B8702626982FC60078BFB2 /* LanguageTranslatorV3 */,
187 | 62EB5C25269E93A9001DA95A /* Moya */,
188 | 62EB5C27269E93C2001DA95A /* CombineMoya */,
189 | );
190 | productName = "Swifty-OCR-Translator";
191 | productReference = 6275307E26945D4900F0524C /* Swifty-OCR-Translator.app */;
192 | productType = "com.apple.product-type.application";
193 | };
194 | /* End PBXNativeTarget section */
195 |
196 | /* Begin PBXProject section */
197 | 6275307626945D4900F0524C /* Project object */ = {
198 | isa = PBXProject;
199 | attributes = {
200 | LastSwiftUpdateCheck = 1250;
201 | LastUpgradeCheck = 1250;
202 | TargetAttributes = {
203 | 6275307D26945D4900F0524C = {
204 | CreatedOnToolsVersion = 12.5.1;
205 | };
206 | };
207 | };
208 | buildConfigurationList = 6275307926945D4900F0524C /* Build configuration list for PBXProject "Swifty-OCR-Translator" */;
209 | compatibilityVersion = "Xcode 9.3";
210 | developmentRegion = en;
211 | hasScannedForEncodings = 0;
212 | knownRegions = (
213 | en,
214 | Base,
215 | );
216 | mainGroup = 6275307526945D4900F0524C;
217 | packageReferences = (
218 | 62B0A6E7269803C500099685 /* XCRemoteSwiftPackageReference "Magnet" */,
219 | 62B8701426981B0E0078BFB2 /* XCRemoteSwiftPackageReference "Defaults" */,
220 | 62B8702526982FC60078BFB2 /* XCRemoteSwiftPackageReference "swift-sdk" */,
221 | 62EB5C24269E93A9001DA95A /* XCRemoteSwiftPackageReference "moya" */,
222 | );
223 | productRefGroup = 6275307F26945D4900F0524C /* Products */;
224 | projectDirPath = "";
225 | projectRoot = "";
226 | targets = (
227 | 6275307D26945D4900F0524C /* Swifty-OCR-Translator */,
228 | );
229 | };
230 | /* End PBXProject section */
231 |
232 | /* Begin PBXResourcesBuildPhase section */
233 | 6275307C26945D4900F0524C /* Resources */ = {
234 | isa = PBXResourcesBuildPhase;
235 | buildActionMask = 2147483647;
236 | files = (
237 | 6275308926945D4A00F0524C /* Preview Assets.xcassets in Resources */,
238 | 6275308626945D4A00F0524C /* Assets.xcassets in Resources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXResourcesBuildPhase section */
243 |
244 | /* Begin PBXSourcesBuildPhase section */
245 | 6275307A26945D4900F0524C /* Sources */ = {
246 | isa = PBXSourcesBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | 6275308426945D4900F0524C /* MainView.swift in Sources */,
250 | 62EB5C1B269E839F001DA95A /* Translator.swift in Sources */,
251 | 62B8701826981DAF0078BFB2 /* MenuView.swift in Sources */,
252 | 62EB5C2A269E93CC001DA95A /* GoogleTranslateAPI.swift in Sources */,
253 | 6275308226945D4900F0524C /* Swifty_OCR_TranslatorApp.swift in Sources */,
254 | 62EB5C2E269EA616001DA95A /* MainViewModel.swift in Sources */,
255 | 62B8701B269823910078BFB2 /* Defaults++.swift in Sources */,
256 | 62EB5C2C269E9626001DA95A /* GoogleTranslateModels.swift in Sources */,
257 | 62B870132698194E0078BFB2 /* MenuViewModel.swift in Sources */,
258 | 62C4E5DE2850858700224761 /* Language.swift in Sources */,
259 | 62EB5C1E269E8421001DA95A /* APIInfo.swift in Sources */,
260 | );
261 | runOnlyForDeploymentPostprocessing = 0;
262 | };
263 | /* End PBXSourcesBuildPhase section */
264 |
265 | /* Begin XCBuildConfiguration section */
266 | 6275308C26945D4A00F0524C /* Debug */ = {
267 | isa = XCBuildConfiguration;
268 | buildSettings = {
269 | ALWAYS_SEARCH_USER_PATHS = NO;
270 | CLANG_ANALYZER_NONNULL = YES;
271 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
273 | CLANG_CXX_LIBRARY = "libc++";
274 | CLANG_ENABLE_MODULES = YES;
275 | CLANG_ENABLE_OBJC_ARC = YES;
276 | CLANG_ENABLE_OBJC_WEAK = YES;
277 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
278 | CLANG_WARN_BOOL_CONVERSION = YES;
279 | CLANG_WARN_COMMA = YES;
280 | CLANG_WARN_CONSTANT_CONVERSION = YES;
281 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
282 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
283 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
284 | CLANG_WARN_EMPTY_BODY = YES;
285 | CLANG_WARN_ENUM_CONVERSION = YES;
286 | CLANG_WARN_INFINITE_RECURSION = YES;
287 | CLANG_WARN_INT_CONVERSION = YES;
288 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
289 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
290 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
291 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
292 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
293 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
294 | CLANG_WARN_STRICT_PROTOTYPES = YES;
295 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
296 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
297 | CLANG_WARN_UNREACHABLE_CODE = YES;
298 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
299 | COPY_PHASE_STRIP = NO;
300 | DEBUG_INFORMATION_FORMAT = dwarf;
301 | ENABLE_STRICT_OBJC_MSGSEND = YES;
302 | ENABLE_TESTABILITY = YES;
303 | GCC_C_LANGUAGE_STANDARD = gnu11;
304 | GCC_DYNAMIC_NO_PIC = NO;
305 | GCC_NO_COMMON_BLOCKS = YES;
306 | GCC_OPTIMIZATION_LEVEL = 0;
307 | GCC_PREPROCESSOR_DEFINITIONS = (
308 | "DEBUG=1",
309 | "$(inherited)",
310 | );
311 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
312 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
313 | GCC_WARN_UNDECLARED_SELECTOR = YES;
314 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
315 | GCC_WARN_UNUSED_FUNCTION = YES;
316 | GCC_WARN_UNUSED_VARIABLE = YES;
317 | MACOSX_DEPLOYMENT_TARGET = 11.3;
318 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
319 | MTL_FAST_MATH = YES;
320 | ONLY_ACTIVE_ARCH = YES;
321 | SDKROOT = macosx;
322 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
323 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
324 | };
325 | name = Debug;
326 | };
327 | 6275308D26945D4A00F0524C /* Release */ = {
328 | isa = XCBuildConfiguration;
329 | buildSettings = {
330 | ALWAYS_SEARCH_USER_PATHS = NO;
331 | CLANG_ANALYZER_NONNULL = YES;
332 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
333 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
334 | CLANG_CXX_LIBRARY = "libc++";
335 | CLANG_ENABLE_MODULES = YES;
336 | CLANG_ENABLE_OBJC_ARC = YES;
337 | CLANG_ENABLE_OBJC_WEAK = YES;
338 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
339 | CLANG_WARN_BOOL_CONVERSION = YES;
340 | CLANG_WARN_COMMA = YES;
341 | CLANG_WARN_CONSTANT_CONVERSION = YES;
342 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
344 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
345 | CLANG_WARN_EMPTY_BODY = YES;
346 | CLANG_WARN_ENUM_CONVERSION = YES;
347 | CLANG_WARN_INFINITE_RECURSION = YES;
348 | CLANG_WARN_INT_CONVERSION = YES;
349 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
350 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
351 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
352 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
353 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
354 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
355 | CLANG_WARN_STRICT_PROTOTYPES = YES;
356 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
357 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
358 | CLANG_WARN_UNREACHABLE_CODE = YES;
359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
360 | COPY_PHASE_STRIP = NO;
361 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
362 | ENABLE_NS_ASSERTIONS = NO;
363 | ENABLE_STRICT_OBJC_MSGSEND = YES;
364 | GCC_C_LANGUAGE_STANDARD = gnu11;
365 | GCC_NO_COMMON_BLOCKS = YES;
366 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
367 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
368 | GCC_WARN_UNDECLARED_SELECTOR = YES;
369 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
370 | GCC_WARN_UNUSED_FUNCTION = YES;
371 | GCC_WARN_UNUSED_VARIABLE = YES;
372 | MACOSX_DEPLOYMENT_TARGET = 11.3;
373 | MTL_ENABLE_DEBUG_INFO = NO;
374 | MTL_FAST_MATH = YES;
375 | SDKROOT = macosx;
376 | SWIFT_COMPILATION_MODE = wholemodule;
377 | SWIFT_OPTIMIZATION_LEVEL = "-O";
378 | };
379 | name = Release;
380 | };
381 | 6275308F26945D4A00F0524C /* Debug */ = {
382 | isa = XCBuildConfiguration;
383 | buildSettings = {
384 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
385 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
386 | CODE_SIGN_ENTITLEMENTS = "Swifty-OCR-Translator/Swifty_OCR_Translator.entitlements";
387 | CODE_SIGN_IDENTITY = "-";
388 | CODE_SIGN_STYLE = Automatic;
389 | COMBINE_HIDPI_IMAGES = YES;
390 | CURRENT_PROJECT_VERSION = 0;
391 | DEVELOPMENT_ASSET_PATHS = "\"Swifty-OCR-Translator/Preview Content\"";
392 | DEVELOPMENT_TEAM = 4BHXT8RHFR;
393 | ENABLE_HARDENED_RUNTIME = YES;
394 | ENABLE_PREVIEWS = YES;
395 | INFOPLIST_FILE = "Swifty-OCR-Translator/Info.plist";
396 | LD_RUNPATH_SEARCH_PATHS = (
397 | "$(inherited)",
398 | "@executable_path/../Frameworks",
399 | );
400 | MACOSX_DEPLOYMENT_TARGET = 11.0;
401 | MARKETING_VERSION = 1.2.0;
402 | PRODUCT_BUNDLE_IDENTIFIER = "dev.PangMo5.Swifty-OCR-Translator";
403 | PRODUCT_NAME = "$(TARGET_NAME)";
404 | SWIFT_VERSION = 5.0;
405 | };
406 | name = Debug;
407 | };
408 | 6275309026945D4A00F0524C /* Release */ = {
409 | isa = XCBuildConfiguration;
410 | buildSettings = {
411 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
412 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
413 | CODE_SIGN_ENTITLEMENTS = "Swifty-OCR-Translator/Swifty_OCR_Translator.entitlements";
414 | CODE_SIGN_IDENTITY = "-";
415 | CODE_SIGN_STYLE = Automatic;
416 | COMBINE_HIDPI_IMAGES = YES;
417 | CURRENT_PROJECT_VERSION = 0;
418 | DEVELOPMENT_ASSET_PATHS = "\"Swifty-OCR-Translator/Preview Content\"";
419 | DEVELOPMENT_TEAM = 4BHXT8RHFR;
420 | ENABLE_HARDENED_RUNTIME = YES;
421 | ENABLE_PREVIEWS = YES;
422 | INFOPLIST_FILE = "Swifty-OCR-Translator/Info.plist";
423 | LD_RUNPATH_SEARCH_PATHS = (
424 | "$(inherited)",
425 | "@executable_path/../Frameworks",
426 | );
427 | MACOSX_DEPLOYMENT_TARGET = 11.0;
428 | MARKETING_VERSION = 1.2.0;
429 | PRODUCT_BUNDLE_IDENTIFIER = "dev.PangMo5.Swifty-OCR-Translator";
430 | PRODUCT_NAME = "$(TARGET_NAME)";
431 | SWIFT_VERSION = 5.0;
432 | };
433 | name = Release;
434 | };
435 | /* End XCBuildConfiguration section */
436 |
437 | /* Begin XCConfigurationList section */
438 | 6275307926945D4900F0524C /* Build configuration list for PBXProject "Swifty-OCR-Translator" */ = {
439 | isa = XCConfigurationList;
440 | buildConfigurations = (
441 | 6275308C26945D4A00F0524C /* Debug */,
442 | 6275308D26945D4A00F0524C /* Release */,
443 | );
444 | defaultConfigurationIsVisible = 0;
445 | defaultConfigurationName = Release;
446 | };
447 | 6275308E26945D4A00F0524C /* Build configuration list for PBXNativeTarget "Swifty-OCR-Translator" */ = {
448 | isa = XCConfigurationList;
449 | buildConfigurations = (
450 | 6275308F26945D4A00F0524C /* Debug */,
451 | 6275309026945D4A00F0524C /* Release */,
452 | );
453 | defaultConfigurationIsVisible = 0;
454 | defaultConfigurationName = Release;
455 | };
456 | /* End XCConfigurationList section */
457 |
458 | /* Begin XCRemoteSwiftPackageReference section */
459 | 62B0A6E7269803C500099685 /* XCRemoteSwiftPackageReference "Magnet" */ = {
460 | isa = XCRemoteSwiftPackageReference;
461 | repositoryURL = "https://github.com/Clipy/Magnet";
462 | requirement = {
463 | kind = upToNextMajorVersion;
464 | minimumVersion = 3.3.0;
465 | };
466 | };
467 | 62B8701426981B0E0078BFB2 /* XCRemoteSwiftPackageReference "Defaults" */ = {
468 | isa = XCRemoteSwiftPackageReference;
469 | repositoryURL = "https://github.com/sindresorhus/Defaults";
470 | requirement = {
471 | kind = upToNextMajorVersion;
472 | minimumVersion = 5.0.0;
473 | };
474 | };
475 | 62B8702526982FC60078BFB2 /* XCRemoteSwiftPackageReference "swift-sdk" */ = {
476 | isa = XCRemoteSwiftPackageReference;
477 | repositoryURL = "https://github.com/watson-developer-cloud/swift-sdk";
478 | requirement = {
479 | kind = upToNextMajorVersion;
480 | minimumVersion = 4.0.0;
481 | };
482 | };
483 | 62EB5C24269E93A9001DA95A /* XCRemoteSwiftPackageReference "moya" */ = {
484 | isa = XCRemoteSwiftPackageReference;
485 | repositoryURL = "https://github.com/moya/moya";
486 | requirement = {
487 | kind = exactVersion;
488 | version = "15.0.0-alpha.1";
489 | };
490 | };
491 | /* End XCRemoteSwiftPackageReference section */
492 |
493 | /* Begin XCSwiftPackageProductDependency section */
494 | 62B0A6E8269803C500099685 /* Magnet */ = {
495 | isa = XCSwiftPackageProductDependency;
496 | package = 62B0A6E7269803C500099685 /* XCRemoteSwiftPackageReference "Magnet" */;
497 | productName = Magnet;
498 | };
499 | 62B8701526981B0E0078BFB2 /* Defaults */ = {
500 | isa = XCSwiftPackageProductDependency;
501 | package = 62B8701426981B0E0078BFB2 /* XCRemoteSwiftPackageReference "Defaults" */;
502 | productName = Defaults;
503 | };
504 | 62B8702626982FC60078BFB2 /* LanguageTranslatorV3 */ = {
505 | isa = XCSwiftPackageProductDependency;
506 | package = 62B8702526982FC60078BFB2 /* XCRemoteSwiftPackageReference "swift-sdk" */;
507 | productName = LanguageTranslatorV3;
508 | };
509 | 62EB5C25269E93A9001DA95A /* Moya */ = {
510 | isa = XCSwiftPackageProductDependency;
511 | package = 62EB5C24269E93A9001DA95A /* XCRemoteSwiftPackageReference "moya" */;
512 | productName = Moya;
513 | };
514 | 62EB5C27269E93C2001DA95A /* CombineMoya */ = {
515 | isa = XCSwiftPackageProductDependency;
516 | package = 62EB5C24269E93A9001DA95A /* XCRemoteSwiftPackageReference "moya" */;
517 | productName = CombineMoya;
518 | };
519 | /* End XCSwiftPackageProductDependency section */
520 | };
521 | rootObject = 6275307626945D4900F0524C /* Project object */;
522 | }
523 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator.xcodeproj/xcuserdata/pangmo5.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ReactiveSwift (Playground) 1.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 6
13 |
14 | ReactiveSwift (Playground) 2.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 7
20 |
21 | ReactiveSwift (Playground).xcscheme
22 |
23 | isShown
24 |
25 | orderHint
26 | 5
27 |
28 | ReactiveSwift-UIExamples (Playground) 1.xcscheme
29 |
30 | isShown
31 |
32 | orderHint
33 | 3
34 |
35 | ReactiveSwift-UIExamples (Playground) 2.xcscheme
36 |
37 | isShown
38 |
39 | orderHint
40 | 4
41 |
42 | ReactiveSwift-UIExamples (Playground).xcscheme
43 |
44 | isShown
45 |
46 | orderHint
47 | 2
48 |
49 | Rx (Playground) 1.xcscheme
50 |
51 | isShown
52 |
53 | orderHint
54 | 9
55 |
56 | Rx (Playground) 2.xcscheme
57 |
58 | isShown
59 |
60 | orderHint
61 | 10
62 |
63 | Rx (Playground).xcscheme
64 |
65 | isShown
66 |
67 | orderHint
68 | 8
69 |
70 | Swifty-OCR-Translator.xcscheme_^#shared#^_
71 |
72 | orderHint
73 | 0
74 |
75 | Test area (Playground) 1.xcscheme
76 |
77 | isShown
78 |
79 | orderHint
80 | 12
81 |
82 | Test area (Playground) 2.xcscheme
83 |
84 | isShown
85 |
86 | orderHint
87 | 13
88 |
89 | Test area (Playground).xcscheme
90 |
91 | isShown
92 |
93 | orderHint
94 | 11
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/APIs/GoogleTranslateAPI.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GoogleTranslateAPI.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/14.
6 | //
7 |
8 | import Defaults
9 | import Foundation
10 | import Moya
11 |
12 | enum GoogleTranslateAPI {
13 | case detect(q: String)
14 | case translate(q: [String], target: String, source: String, format: String = "text")
15 | case supportedLanguages
16 | }
17 |
18 | extension GoogleTranslateAPI: TargetType {
19 | var baseURL: URL {
20 | URL(string: "https://translation.googleapis.com")!
21 | }
22 |
23 | var path: String {
24 | switch self {
25 | case .detect:
26 | return "/language/translate/v2/detect"
27 | case .translate:
28 | return "/language/translate/v2"
29 | case .supportedLanguages:
30 | return "/language/translate/v2/languages"
31 | }
32 | }
33 |
34 | var method: Moya.Method {
35 | switch self {
36 | case .detect, .translate:
37 | return .post
38 | case .supportedLanguages:
39 | return .get
40 | }
41 | }
42 |
43 | var sampleData: Data {
44 | "{".data(using: .utf8)!
45 | }
46 |
47 | var task: Task {
48 | switch self {
49 | case let .detect(q):
50 | var parameters = [String: Any]()
51 | parameters["key"] = Defaults[.apiInfoDict][.google]?.key
52 | parameters["q"] = q
53 | return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
54 | case let .translate(q, target, source, format):
55 | var parameters = [String: Any]()
56 | parameters["key"] = Defaults[.apiInfoDict][.google]?.key
57 | parameters["q"] = q
58 | parameters["target"] = target
59 | parameters["source"] = source
60 | parameters["format"] = format
61 | return .requestParameters(parameters: parameters, encoding: URLEncoding(arrayEncoding: .noBrackets))
62 | case .supportedLanguages:
63 | var parameters = [String: Any]()
64 | parameters["key"] = Defaults[.apiInfoDict][.google]?.key
65 | return .requestParameters(parameters: parameters, encoding: URLEncoding.default)
66 | }
67 | }
68 |
69 | var headers: [String : String]? {
70 | nil
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-16.png",
5 | "idiom" : "mac",
6 | "scale" : "1x",
7 | "size" : "16x16"
8 | },
9 | {
10 | "filename" : "icon-32.png",
11 | "idiom" : "mac",
12 | "scale" : "2x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "icon-33.png",
17 | "idiom" : "mac",
18 | "scale" : "1x",
19 | "size" : "32x32"
20 | },
21 | {
22 | "filename" : "icon-64.png",
23 | "idiom" : "mac",
24 | "scale" : "2x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "icon-128.png",
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "filename" : "icon-256.png",
35 | "idiom" : "mac",
36 | "scale" : "2x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "icon-257.png",
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "256x256"
44 | },
45 | {
46 | "filename" : "icon-512.png",
47 | "idiom" : "mac",
48 | "scale" : "2x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "icon-513.png",
53 | "idiom" : "mac",
54 | "scale" : "1x",
55 | "size" : "512x512"
56 | },
57 | {
58 | "filename" : "icon-1024.png",
59 | "idiom" : "mac",
60 | "scale" : "2x",
61 | "size" : "512x512"
62 | }
63 | ],
64 | "info" : {
65 | "author" : "xcode",
66 | "version" : 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-1024.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-128.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-16.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-256.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-257.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-257.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-32.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-33.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-512.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-513.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-513.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PangMo5/SwiftyCrow/9c91a60245e8dbb7c4575cd2f90926e1c41237c0/Swifty-OCR-Translator/Assets.xcassets/AppIcon.appiconset/icon-64.png
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Enums/Language.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Language.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2022/06/08.
6 | //
7 |
8 | import Foundation
9 | import Defaults
10 |
11 | enum Language: String, CaseIterable, DefaultsSerializable {
12 | case en
13 | case ko
14 | case ja
15 | case fr
16 | case it
17 | case de
18 | case es
19 | case pt
20 | case zh
21 |
22 | var toLocaleStrings: [String] {
23 | switch self {
24 | case .en:
25 | return ["en-US"]
26 | case .ko:
27 | return ["ko-KR"]
28 | case .ja:
29 | return ["ja-JP"]
30 | case .fr:
31 | return ["fr-FR"]
32 | case .it:
33 | return ["it-IT"]
34 | case .de:
35 | return ["de-DE"]
36 | case .es:
37 | return ["es-ES"]
38 | case .pt:
39 | return ["pt-BR"]
40 | case .zh:
41 | return ["zh-Hans", "zh-Hant"]
42 | }
43 | }
44 |
45 | var toLocalized: String {
46 | Locale.current.localizedString(forLanguageCode: rawValue) ?? "unknown"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Enums/Translator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Translator.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/14.
6 | //
7 |
8 | import Defaults
9 | import Foundation
10 |
11 | enum Translator: String, Codable, CaseIterable, LosslessStringConvertible, DefaultsSerializable {
12 | enum Field {
13 | case url
14 | case key
15 | }
16 |
17 | case ibm
18 | case google
19 |
20 | init?(_ description: String) {
21 | self.init(rawValue: description)
22 | }
23 |
24 | var description: String {
25 | rawValue
26 | }
27 |
28 | var localized: String {
29 | switch self {
30 | case .ibm:
31 | return "IBM Watson"
32 | case .google:
33 | return "Google Cloud"
34 | }
35 | }
36 |
37 | var requierdFields: [Field] {
38 | switch self {
39 | case .ibm:
40 | return [.url, .key]
41 | case .google:
42 | return [.key]
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Extensions/Defaults++.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Defaults++.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/09.
6 | //
7 |
8 | import Defaults
9 |
10 | extension Defaults.Keys {
11 | static let selectedSourceLanuage = Key("selectedSourceLanuage", default: .en)
12 | static let selectedTargetLanuage = Key("selectedTargetLanuage", default: "")
13 | static let selectedTranslator = Key("selectedTranslator", default: .allCases.first!)
14 | static let apiInfoDict = Key<[Translator: APIInfo]>("apiInfoDict", default: [:])
15 | }
16 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/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 | $(MARKETING_VERSION)
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | LSApplicationCategoryType
22 | public.app-category.utilities
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Models/APIInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // APIInfo.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/14.
6 | //
7 |
8 | import Defaults
9 | import Foundation
10 |
11 | struct APIInfo: Codable, DefaultsSerializable {
12 | var url: String
13 | var key: String
14 | }
15 |
16 | extension Dictionary where Key == Translator, Value == APIInfo {
17 | var current: APIInfo {
18 | get {
19 | self[Defaults[.selectedTranslator]] ?? .init(url: "", key: "")
20 | }
21 | set {
22 | self[Defaults[.selectedTranslator]] = newValue
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Models/GoogleTranslateModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GoogleTranslateModel.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/14.
6 | //
7 |
8 | import Foundation
9 |
10 | enum GoogleTranslateAPIResponse {}
11 |
12 | extension GoogleTranslateAPIResponse {
13 | struct Languages: Codable {
14 | var languages: [Language]
15 | }
16 |
17 | struct Detections: Codable {
18 | var detections: [Detection]
19 | }
20 |
21 | struct Translations: Codable {
22 | var translations: [Translation]
23 | }
24 | }
25 |
26 | extension GoogleTranslateAPIResponse {
27 | struct Language: Codable {
28 | var language: String
29 | }
30 |
31 | struct Detection: Codable {
32 | var confidence: Double
33 | var isReliable: Bool
34 | var language: String
35 | }
36 |
37 | struct Translation: Codable {
38 | var translatedText: String
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Swifty_OCR_Translator.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.temporary-exception.mach-register.global-name
8 | com.apple.screencapture.interactive
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Swifty_OCR_TranslatorApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Swifty_OCR_TranslatorApp.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/06.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct Swifty_OCR_TranslatorApp: App {
12 | @NSApplicationDelegateAdaptor(AppDelegate.self)
13 | var appDelegate
14 |
15 | var body: some Scene {
16 | WindowGroup {
17 | MainView()
18 | .frame(minWidth: 300, idealWidth: 300, minHeight: 200, idealHeight: 200)
19 | }
20 | }
21 | }
22 |
23 | class AppDelegate: NSObject, NSApplicationDelegate {
24 | var statusItem: NSStatusItem?
25 |
26 | func applicationDidFinishLaunching(_ notification: Notification) {
27 | let contentView = MenuView()
28 | statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
29 | let view = NSHostingView(rootView: contentView)
30 | view.frame = NSRect(x: 0, y: 0, width: 400, height: 400)
31 |
32 | let menuItem = NSMenuItem()
33 | menuItem.view = view
34 |
35 | let menu = NSMenu()
36 | menu.addItem(menuItem)
37 |
38 | statusItem?.menu = menu
39 | statusItem?.button?.image = NSImage(systemSymbolName: "mail.and.text.magnifyingglass", accessibilityDescription: nil)
40 | statusItem?.button?.image?.isTemplate = true
41 |
42 | NotificationCenter.default.addObserver(forName: .init(rawValue: "FinishedTranslate"), object: nil, queue: nil) { _ in
43 | self.statusItem?.menu?.popUp(positioning: menuItem,
44 | at: NSPoint(x: 0, y: self.statusItem?.button?.frame.height ?? 0),
45 | in: self.statusItem?.button)
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/ViewModels/MainViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewModel.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/14.
6 | //
7 |
8 | import Combine
9 | import CombineMoya
10 | import Defaults
11 | import Foundation
12 | import LanguageTranslatorV3
13 | import Moya
14 |
15 | final class MainViewModel: ObservableObject {
16 | private var cancellables = Set()
17 | fileprivate var googleTranslateProvider = MoyaProvider()
18 |
19 | @Published
20 | var supportedOCRLanguages = Language.allCases
21 | @Published
22 | var supportedTargetLanuages = [String]()
23 |
24 | init() {
25 | Defaults.publisher(.selectedTranslator)
26 | .map(\.newValue)
27 | .sink(receiveValue: updateTargetLanuages(with:))
28 | .store(in: &cancellables)
29 | updateTargetLanuages(with: Defaults[.selectedTranslator])
30 | }
31 |
32 | func updateTargetLanuages(with translator: Translator) {
33 | switch translator {
34 | case .ibm:
35 | let authenticator = WatsonIAMAuthenticator(apiKey: Defaults[.apiInfoDict].current.key)
36 | let languageTranslator = LanguageTranslator(version: "2018-05-01", authenticator: authenticator)
37 | languageTranslator.serviceURL = Defaults[.apiInfoDict].current.url
38 | languageTranslator.listLanguages { [weak self] response, error in
39 |
40 | guard let supportedLanuages = response?.result else {
41 | print(error?.localizedDescription ?? "unknown error")
42 | return
43 | }
44 |
45 | DispatchQueue.main.async {
46 | self?.supportedTargetLanuages = supportedLanuages.languages.compactMap(\.language)
47 | .sorted(by: { $0.toLocalized < $1.toLocalized })
48 | }
49 | }
50 | case .google:
51 | googleTranslateProvider.requestPublisher(.supportedLanguages)
52 | .map(GoogleTranslateAPIResponse.Languages.self, atKeyPath: "data")
53 | .map {
54 | $0.languages.map(\.language).sorted(by: { $0.toLocalized < $1.toLocalized })
55 | }
56 | .replaceError(with: [])
57 | .assign(to: \.supportedTargetLanuages, on: self)
58 | .store(in: &cancellables)
59 | }
60 | }
61 | }
62 |
63 | extension String {
64 | var toLocalized: String {
65 | Locale.current.localizedString(forLanguageCode: self) ?? "unknown"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/ViewModels/MenuViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MenuViewModel.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/09.
6 | //
7 |
8 | import AppKit
9 | import Combine
10 | import CombineMoya
11 | import Defaults
12 | import LanguageTranslatorV3
13 | import Magnet
14 | import Moya
15 | import Vision
16 |
17 | final class MenuViewModel: ObservableObject {
18 | private var cancellables = Set()
19 |
20 | fileprivate var googleTranslateProvider = MoyaProvider()
21 |
22 | @Published
23 | var strs = [String]()
24 | @Published
25 | var translated = [String]()
26 | @Published
27 | var latestTranslator: Translator?
28 |
29 | init() {
30 | if let keyCombo = KeyCombo(key: .one, cocoaModifiers: [.command, .shift]) {
31 | let hotKey = HotKey(identifier: "CommandShiftOne", keyCombo: keyCombo) { _ in
32 | self.takeScreenshot()
33 | }
34 | hotKey.register()
35 | }
36 | }
37 |
38 | fileprivate func takeScreenshot() {
39 | let path = FileManager.default.temporaryDirectory.appendingPathComponent("\(UUID().uuidString).png")
40 | let task = Process()
41 | task.launchPath = "/usr/sbin/screencapture"
42 | task.arguments = ["-i", "-r", path.path]
43 | task.launch()
44 | task.waitUntilExit()
45 | requestRecognizeText(with: path.path)
46 | }
47 |
48 | fileprivate func requestRecognizeText(with urlPath: String) {
49 | let image = NSImage(contentsOfFile: urlPath)
50 | guard let cgImage = image?.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return }
51 | // Create a new image-request handler.
52 | let requestHandler = VNImageRequestHandler(cgImage: cgImage)
53 |
54 | let request = VNRecognizeTextRequest(completionHandler: recognizeTextHandler(request:error:))
55 | request.recognitionLevel = .accurate
56 | var languages = Language.allCases
57 | languages.removeAll(where: { $0 == Defaults[.selectedSourceLanuage] })
58 | languages.insert(Defaults[.selectedSourceLanuage], at: 0)
59 | request.recognitionLanguages = languages.map(\.toLocaleStrings).flatMap { $0 }
60 | request.usesLanguageCorrection = true
61 | do {
62 | try requestHandler.perform([request])
63 | } catch {
64 | print("Unable to perform the requests: \(error).")
65 | }
66 | }
67 |
68 | fileprivate func recognizeTextHandler(request: VNRequest, error: Error?) {
69 | guard let observations =
70 | request.results as? [VNRecognizedTextObservation]
71 | else {
72 | return
73 | }
74 | let recognizedStrings = observations.compactMap { observation in
75 | observation.topCandidates(1).first?.string
76 | }
77 |
78 | print(recognizedStrings)
79 | strs = recognizedStrings
80 | translate(textList: strs)
81 | }
82 |
83 | fileprivate func translate(textList: [String]) {
84 | switch Defaults[.selectedTranslator] {
85 | case .ibm:
86 | translateWithIBM(textList: textList)
87 | case .google:
88 | translateWithGoogle(textList: textList)
89 | }
90 | }
91 |
92 | fileprivate func translateWithIBM(textList: [String]) {
93 | let authenticator = WatsonIAMAuthenticator(apiKey: Defaults[.apiInfoDict].current.key)
94 | let languageTranslator = LanguageTranslator(version: "2018-05-01", authenticator: authenticator)
95 | languageTranslator.serviceURL = Defaults[.apiInfoDict].current.url
96 |
97 | languageTranslator
98 | .translate(
99 | text: textList,
100 | modelID: "\(Defaults[.selectedSourceLanuage].rawValue)-\(Defaults[.selectedTargetLanuage])"
101 | ) { [weak self] response, error in
102 |
103 | guard let translation = response?.result else {
104 | print(error?.localizedDescription ?? "unknown error")
105 | return
106 | }
107 |
108 | DispatchQueue.main.async {
109 | self?.translated = translation.translations.map(\.translation)
110 | self?.finishedTranslate()
111 | }
112 | print(translation)
113 | }
114 | }
115 |
116 | fileprivate func translateWithGoogle(textList: [String]) {
117 | googleTranslateProvider
118 | .requestPublisher(.translate(q: textList, target: Defaults[.selectedTargetLanuage], source: Defaults[.selectedSourceLanuage].rawValue))
119 | .map(GoogleTranslateAPIResponse.Translations.self, atKeyPath: "data")
120 | .print()
121 | .replaceError(with: .init(translations: []))
122 | .map {
123 | $0.translations.map(\.translatedText)
124 | }
125 | .sink(receiveValue: { [weak self] response in
126 | self?.translated = response
127 | self?.finishedTranslate()
128 | })
129 | .store(in: &cancellables)
130 | }
131 |
132 | func finishedTranslate() {
133 | latestTranslator = Defaults[.selectedTranslator]
134 | NotificationCenter.default.post(name: .init(rawValue: "FinishedTranslate"), object: nil)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Views/MainView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/06.
6 | //
7 |
8 | import Defaults
9 | import SwiftUI
10 |
11 | struct MainView: View {
12 | @StateObject
13 | var viewModel = MainViewModel()
14 | @Default(.selectedSourceLanuage)
15 | var selectedSourceLanuage
16 | @Default(.selectedTargetLanuage)
17 | var selectedTargetLanuage
18 | @Default(.selectedTranslator)
19 | var selectedTranslator
20 | @Default(.apiInfoDict)
21 | var apiInfoDict
22 |
23 | var body: some View {
24 | Form {
25 | Picker("Source Language", selection: $selectedSourceLanuage) {
26 | ForEach(viewModel.supportedOCRLanguages, id: \.self) {
27 | Text($0.toLocalized)
28 | .tag($0)
29 | }
30 | }
31 | Picker("Target Language", selection: $selectedTargetLanuage) {
32 | ForEach(viewModel.supportedTargetLanuages, id: \.self) {
33 | Text($0.toLocalized)
34 | .tag($0)
35 | }
36 | }
37 | Picker("Translator", selection: $selectedTranslator) {
38 | ForEach(Translator.allCases, id: \.self) {
39 | Text($0.localized)
40 | .tag($0)
41 | }
42 | }
43 | if selectedTranslator.requierdFields.contains(.url) {
44 | TextField("API URL", text: $apiInfoDict.current.url)
45 | }
46 | if selectedTranslator.requierdFields.contains(.key) {
47 | SecureField("API Key", text: $apiInfoDict.current.key)
48 | }
49 | }
50 | .padding()
51 | }
52 | }
53 |
54 | struct ContentView_Previews: PreviewProvider {
55 | static var previews: some View {
56 | MainView()
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Swifty-OCR-Translator/Views/MenuView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MenuView.swift
3 | // Swifty-OCR-Translator
4 | //
5 | // Created by PangMo5 on 2021/07/09.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct MenuView: View {
11 | @ObservedObject
12 | var viewModel = MenuViewModel()
13 |
14 | var body: some View {
15 | if !viewModel.strs.isEmpty || !viewModel.translated.isEmpty {
16 | ScrollView {
17 | LazyVStack(alignment: .leading) {
18 | Text("Source")
19 | .font(.title)
20 | Divider()
21 | ForEach(viewModel.strs, id: \.self) {
22 | Text($0)
23 | }
24 | Divider()
25 | Text("Target")
26 | .font(.title)
27 | Divider()
28 | ForEach(viewModel.translated, id: \.self) {
29 | Text($0)
30 | }
31 | if let latestTranslator = viewModel.latestTranslator?.localized {
32 | Text("Translated by \(latestTranslator)")
33 | .font(.callout)
34 | .frame(maxWidth: .infinity, alignment: .trailing)
35 | .padding(.top, 16)
36 | }
37 | }
38 | .padding()
39 | }
40 | } else {
41 | Text("Capture image using [cmd + shift + 1]")
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------