├── .gitignore
├── Translateme.sketchplugin
└── Contents
│ ├── Resources
│ ├── .gitkeep
│ └── logo@2x.png
│ └── Sketch
│ ├── main.cocoascript
│ ├── manifest.json
│ ├── common.js
│ └── translator.js
├── assets
├── demo.gif
└── sketchpacks.png
├── appcast.xml
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | assets/.DS_Store
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/Translateme.sketchplugin/Contents/Resources/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eddiesigner/sketch-translate-me/HEAD/assets/demo.gif
--------------------------------------------------------------------------------
/assets/sketchpacks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eddiesigner/sketch-translate-me/HEAD/assets/sketchpacks.png
--------------------------------------------------------------------------------
/Translateme.sketchplugin/Contents/Resources/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eddiesigner/sketch-translate-me/HEAD/Translateme.sketchplugin/Contents/Resources/logo@2x.png
--------------------------------------------------------------------------------
/Translateme.sketchplugin/Contents/Sketch/main.cocoascript:
--------------------------------------------------------------------------------
1 | @import "translator.js";
2 |
3 | function runSimpleTranslation (context) {
4 | var translator = new Translator();
5 | translator.translateSingleText(context);
6 | }
7 |
8 | function runArtboardTranslation (context) {
9 | var translator = new Translator();
10 | translator.translateArtboard(context);
11 | }
12 |
13 | function runEverythingTranslation (context) {
14 | var translator = new Translator();
15 | translator.translateEverything(context);
16 | }
17 |
18 | function runSetApiKey (context) {
19 | var translator = new Translator();
20 | translator.openApiKeyWindow(context);
21 | }
--------------------------------------------------------------------------------
/Translateme.sketchplugin/Contents/Sketch/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "author" : "Craftbot",
3 | "bundleVersion" : 1,
4 | "commands" : [
5 | {
6 | "script" : "main.cocoascript",
7 | "name" : "Translate Layer",
8 | "handler" : "runSimpleTranslation",
9 | "identifier" : "scriptSingle",
10 | "shortcut" : "shift cmd w"
11 | },
12 | {
13 | "script" : "main.cocoascript",
14 | "name" : "Translate Artboard",
15 | "handler" : "runArtboardTranslation",
16 | "identifier" : "scriptArtboard",
17 | "shortcut" : "shift cmd x"
18 | },
19 | {
20 | "script" : "main.cocoascript",
21 | "name" : "Translate Everything",
22 | "handler" : "runEverythingTranslation",
23 | "identifier" : "scriptEverything",
24 | "shortcut" : "shift cmd y"
25 | },
26 | {
27 | "script" : "main.cocoascript",
28 | "name" : "Set Google API Key...",
29 | "handler" : "runSetApiKey",
30 | "identifier" : "scriptKey",
31 | "shortcut" : "shift cmd k"
32 | }
33 | ],
34 | "menu" : {
35 | "items" : [
36 | "scriptSingle",
37 | "scriptArtboard",
38 | "scriptEverything",
39 | "scriptKey"
40 | ],
41 | "title" : "Translate.me"
42 | },
43 | "compatibleVersion" : 4,
44 | "homepage" : "https://github.com/eddiesigner/sketch-translate-me",
45 | "identifier" : "io.craftbot.sketch.translate-me",
46 | "appcast": "https://raw.githubusercontent.com/eddiesigner/sketch-translate-me/master/appcast.xml",
47 | "version" : "0.1.1",
48 | "description" : "Plugin to translate Sketch files in any language",
49 | "authorEmail" : "",
50 | "name" : "Translate.me"
51 | }
52 |
--------------------------------------------------------------------------------
/appcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Translate.me
5 | http://sparkle-project.org/files/sparkletestcast.xml
6 | Plugin to translate Sketch files in any language
7 | en
8 | -
9 | Version 0.0.1
10 |
11 |
13 | Alpha version
14 |
15 | ]]>
16 |
17 |
18 |
19 | -
20 | Version 0.0.2
21 |
22 |
24 | New documentation
25 | New icon
26 |
27 | ]]>
28 |
29 |
30 |
31 | -
32 | Version 0.1.0
33 |
34 |
36 | The plugin now uses your own Google API Key
37 | Improvements and bugfixes
38 | New documentation
39 |
40 | ]]>
41 |
42 |
43 |
44 | -
45 | Version 0.1.1
46 |
47 |
49 | Fixes the problem that made the plugin not work after installation
50 |
51 | ]]>
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Translate.me 0.1.1 - Sketch App Plugin
2 |
3 | Translations. Simplified.
4 |
5 | Translate your Sketch text layers, artboards and pages in over 100 languages with Translate.me plugin. Powered by Google.
6 |
7 | Translate.me helps you to save time, understand and communicate across your international team or app.
8 |
9 | If you use it and you like it, please consider to make a donation to support its development! 🙏🏼
10 |
11 |
12 |
13 | 
14 |
15 | ## How it works?
16 |
17 | 1. Translate.me automatically detects the language which you used on your file.
18 |
19 | 2. Choose over 100 languages
20 |
21 | 3. Witness the plugin in action
22 |
23 | ##### Translate Layer
24 | Plugins > Translate.me > Translate Layer
25 |
26 | Shortcut: Shift+Cmd+W
27 | ##### Translate Artboard
28 | Plugins > Translate.me > Translate Artboard
29 |
30 | Shortcut: Shift+Cmd+X
31 |
32 | ##### Translate Everything
33 | Plugins > Translate.me > Translate Everything
34 |
35 | Shortcut: Shift+Cmd+Y
36 |
37 | ##### Set Google API Key...
38 | Plugins > Translate.me > Set Google API Key...
39 |
40 | Shortcut: Shift+Cmd+K
41 |
42 |
43 | ## Installation
44 |
45 | [](https://www.sketchpacks.com/eddiesigner/sketch-translate-me/install)
46 |
47 |
48 | #### Install with Sketch Runner
49 | With Sketch Runner, just go to the `install` command and search for `Translate.me`. Runner allows you to manage plugins and do much more to speed up your workflow in Sketch. [Download Runner here](http://www.sketchrunner.com).
50 |
51 | 
52 |
53 | #### Manual
54 |
55 | 1. [Download the Zip](https://github.com/eddiesigner/sketch-translate-me/archive/master.zip) and unzip the package
56 | 2. Double click on `Translateme.sketchplugin` for auto installation
57 |
58 | ## Configuration
59 |
60 | Be sure to read [this article](https://github.com/eddiesigner/sketch-translate-me/wiki/Generate-a-Google-API-Key) as you will need a Google API key to use the plugin.
61 | This article describes the process for obtaining a key and how to integrate it into the plugin, don't worry, it's easy ;)
62 |
63 | ## Compatibility
64 |
65 | The plugin is compatible with Sketch 4+.
66 |
67 | ## Contact
68 |
69 | If you have any questions or troubles with our product, please feel free to open an issue [here](https://github.com/eddiesigner/sketch-translate-me/issues).
70 |
71 | If you prefer, you can send an email to: [hello@craftbot.io](mailto:hello@craftbot.io)
72 |
--------------------------------------------------------------------------------
/Translateme.sketchplugin/Contents/Sketch/common.js:
--------------------------------------------------------------------------------
1 | var pluginIdentifier = "io.craftbot.sketch.translate-me";
2 | var app = NSApplication.sharedApplication();
3 | var googleApiKey = getOption('apiKey', '');
4 |
5 |
6 | function checkCount (context) {
7 | if (context.selection.count() != 1) {
8 | app.displayDialog_withTitle("You have to select something.", "Wrong shape layer selection");
9 | return false;
10 | }
11 |
12 | return true;
13 | }
14 |
15 |
16 | function checkTextLayerType (context) {
17 | var layer = context.selection[0];
18 |
19 | if ([layer class] != MSTextLayer) {
20 | app.displayDialog_withTitle("Your selection was a “" + [layer name] + "”, that is not a text layer. Please select a text layer.", "Text layer only");
21 | return false;
22 | }
23 |
24 | return true;
25 | }
26 |
27 |
28 | function duplicatePage (context, language) {
29 | var doc = context.document;
30 | var page = [doc currentPage];
31 | var newPage = [page copy];
32 |
33 | newPage.setName([page name] + " " + language);
34 |
35 | [[doc documentData] addPage:newPage];
36 | [doc setCurrentPage:newPage];
37 |
38 | return newPage;
39 | }
40 |
41 |
42 | function checkArtboardLayerType (context) {
43 | var layer = context.selection[0];
44 |
45 | if ([layer class] != MSArtboardGroup) {
46 | app.displayDialog_withTitle("Your selection was a “" + [layer name] + "”, that is not an artboard. Please select an artboard.", "Artboard only");
47 | return false;
48 | }
49 |
50 | return true;
51 | }
52 |
53 |
54 | function selectLayersOfTypeInContainer (doc, layerType, containerLayer) {
55 | var scope = (typeof containerLayer !== 'undefined') ? [containerLayer children] : [[doc currentPage] children];
56 | var predicate = NSPredicate.predicateWithFormat("(className == %@)", layerType);
57 | var layers = [scope filteredArrayUsingPredicate:predicate];
58 | var page = (layerType === 'MSArtboardGroup') ? containerLayer : [doc currentPage];
59 |
60 | if (page.deselectAllLayers) {
61 | page.deselectAllLayers();
62 | } else {
63 | page.changeSelectionBySelectingLayers_([]);
64 | }
65 |
66 | var loop = [layers objectEnumerator];
67 | var layers = [];
68 | var layer;
69 |
70 | while (layer = [loop nextObject]) {
71 | layers.push(layer);
72 |
73 | if (MSApplicationMetadata.metadata().appVersion > 45) {
74 | layer.select_byExpandingSelection(true, true);
75 | } else {
76 | layer.select_byExtendingSelection(true, true);
77 | }
78 | }
79 |
80 | return layers;
81 | }
82 |
83 |
84 | function handleAlertResponse (dialog, responseCode) {
85 | if (responseCode == "1000") {
86 | return dialog.viewAtIndex(0).indexOfSelectedItem();
87 | } else {
88 | return null;
89 | }
90 | }
91 |
92 |
93 | function handleKeyAlertResponse (dialog, responseCode) {
94 | if (responseCode == "1000") {
95 | var apiKeyValue = dialog.viewAtIndex(0).stringValue();
96 |
97 | setPreferences('apiKey', apiKeyValue);
98 |
99 | return true;
100 | } else {
101 | return false;
102 | }
103 | }
104 |
105 |
106 | function createSelect (options) {
107 | var select = NSPopUpButton.alloc().initWithFrame(NSMakeRect(0, 0, 200, 28));
108 |
109 | select.addItemsWithTitles(options);
110 | select.selectItemAtIndex(0);
111 |
112 | return select;
113 | }
114 |
115 |
116 | function detectLenguage (text) {
117 | var escapedText = text.replace('"', '\"');
118 | var data = JSON.stringify({q:escapedText});
119 |
120 | var languageDetected = networkRequest(["-X", "POST", "https://translation.googleapis.com/language/translate/v2/detect?key=" + googleApiKey, "-H", "Content-Type: application/json; charset=utf-8", "-d", data]);
121 |
122 | return languageDetected.data.detections[0][0].language;
123 | }
124 |
125 |
126 | function getSingleTranslation (text, baseLanguage, toLanguage) {
127 | var escapedText = text.replace('"', '\"');
128 | var data = JSON.stringify({q:escapedText, source: baseLanguage, target: toLanguage});
129 |
130 | var singleTranslation = networkRequest(["-X", "POST", "https://translation.googleapis.com/language/translate/v2?key=" + googleApiKey, "-H", "Content-Type: application/json; charset=utf-8", "-d", data]);
131 |
132 | return singleTranslation.data.translations[0].translatedText.replace(/"/g, '"');
133 | }
134 |
135 |
136 | function networkRequest (args) {
137 | var task = NSTask.alloc().init();
138 | task.setLaunchPath("/usr/bin/curl");
139 | task.setArguments(args);
140 |
141 | var outputPipe = [NSPipe pipe];
142 | [task setStandardOutput:outputPipe];
143 | task.launch();
144 |
145 | var responseData = [[outputPipe fileHandleForReading] readDataToEndOfFile];
146 | var responseString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]];
147 | var parsed = tryParseJSON(responseString);
148 |
149 | if (!parsed) {
150 | log("Error invoking curl");
151 | log("args:");
152 | log(args);
153 | log("responseString");
154 | log(responseString);
155 | throw "Error communicating with server";
156 | }
157 |
158 | return parsed;
159 | }
160 |
161 |
162 | function tryParseJSON (jsonString){
163 | try {
164 | var o = JSON.parse(jsonString);
165 |
166 | if (o && typeof o === "object" && o !== null) {
167 | return o;
168 | }
169 | }
170 | catch (e) { }
171 |
172 | return false;
173 | }
174 |
175 |
176 | function getOption(key, defaultValue) {
177 | return getPreferences(key, defaultValue);
178 | }
179 |
180 |
181 | function getPreferences(key, defaultValue) {
182 | var userDefaults = NSUserDefaults.standardUserDefaults();
183 |
184 | if (!userDefaults.dictionaryForKey(pluginIdentifier)) {
185 | var defaultPreferences = NSMutableDictionary.alloc().init();
186 |
187 | userDefaults.setObject_forKey(defaultPreferences, pluginIdentifier);
188 | userDefaults.synchronize();
189 | }
190 |
191 | var value = userDefaults.dictionaryForKey(pluginIdentifier).objectForKey(key);
192 |
193 | return (value === null) ? defaultValue : value;
194 | }
195 |
196 |
197 | function setPreferences(key, value) {
198 | var userDefaults = NSUserDefaults.standardUserDefaults();
199 | var preferences;
200 |
201 | if (!userDefaults.dictionaryForKey(pluginIdentifier)) {
202 | preferences = NSMutableDictionary.alloc().init();
203 | } else {
204 | preferences = NSMutableDictionary.dictionaryWithDictionary(userDefaults.dictionaryForKey(pluginIdentifier));
205 | }
206 |
207 | preferences.setObject_forKey(value, key);
208 |
209 | userDefaults.setObject_forKey(preferences, pluginIdentifier);
210 | userDefaults.synchronize();
211 | }
--------------------------------------------------------------------------------
/Translateme.sketchplugin/Contents/Sketch/translator.js:
--------------------------------------------------------------------------------
1 | @import "common.js";
2 |
3 | function Translator () {}
4 |
5 | Translator.prototype.languageLabels = [
6 | 'Afrikaans',
7 | 'Albanian',
8 | 'Amharic',
9 | 'Arabic',
10 | 'Armenian',
11 | 'Azeerbaijani',
12 | 'Basque',
13 | 'Belarusian',
14 | 'Bengali',
15 | 'Bosnian',
16 | 'Bulgarian',
17 | 'Catalan',
18 | 'Cebuano',
19 | 'Chinese (Simplified)',
20 | 'Chinese (Traditional)',
21 | 'Corsican',
22 | 'Croatian',
23 | 'Czech',
24 | 'Danish',
25 | 'Dutch',
26 | 'English',
27 | 'Esperanto',
28 | 'Estonian',
29 | 'Finnish',
30 | 'French',
31 | 'Frisian',
32 | 'Galician',
33 | 'Georgian',
34 | 'German',
35 | 'Greek',
36 | 'Gujarati',
37 | 'Haitian Creole',
38 | 'Hausa',
39 | 'Hawaiian',
40 | 'Hebrew',
41 | 'Hindi',
42 | 'Hmong',
43 | 'Hungarian',
44 | 'Icelandic',
45 | 'Igbo',
46 | 'Indonesian',
47 | 'Irish',
48 | 'Italian',
49 | 'Japanese',
50 | 'Javanese',
51 | 'Kannada',
52 | 'Kazakh',
53 | 'Khmer',
54 | 'Korean',
55 | 'Kurdish',
56 | 'Kyrgyz',
57 | 'Lao',
58 | 'Latin',
59 | 'Latvian',
60 | 'Lithuanian',
61 | 'Luxembourgish',
62 | 'Macedonian',
63 | 'Malagasy',
64 | 'Malay',
65 | 'Malayalam',
66 | 'Maltese',
67 | 'Maori',
68 | 'Marathi',
69 | 'Mongolian',
70 | 'Myanmar (Burmese)',
71 | 'Nepali',
72 | 'Norwegian',
73 | 'Nyanja (Chichewa)',
74 | 'Pashto',
75 | 'Persian',
76 | 'Polish',
77 | 'Portuguese (Portugal, Brazil)',
78 | 'Punjabi',
79 | 'Romanian',
80 | 'Russian',
81 | 'Samoan',
82 | 'Scots Gaelic',
83 | 'Serbian',
84 | 'Sesotho',
85 | 'Shona',
86 | 'Sindhi',
87 | 'Sinhala (Sinhalese)',
88 | 'Slovak',
89 | 'Slovenian',
90 | 'Somali',
91 | 'Spanish',
92 | 'Sundanese',
93 | 'Swahili',
94 | 'Swedish',
95 | 'Tagalog (Filipino)',
96 | 'Tajik',
97 | 'Tamil',
98 | 'Telugu',
99 | 'Thai',
100 | 'Turkish',
101 | 'Ukrainian',
102 | 'Urdu',
103 | 'Uzbek',
104 | 'Vietnamese',
105 | 'Welsh',
106 | 'Xhosa',
107 | 'Yiddish',
108 | 'Yoruba',
109 | 'Zulu'
110 | ];
111 |
112 |
113 | Translator.prototype.languageCodes = [
114 | 'af',
115 | 'sq',
116 | 'am',
117 | 'ar',
118 | 'hy',
119 | 'az',
120 | 'eu',
121 | 'be',
122 | 'bn',
123 | 'bs',
124 | 'bg',
125 | 'ca',
126 | 'ceb',
127 | 'zh-CN',
128 | 'zh-TW',
129 | 'co',
130 | 'hr',
131 | 'cs',
132 | 'da',
133 | 'nl',
134 | 'en',
135 | 'eo',
136 | 'et',
137 | 'fi',
138 | 'fr',
139 | 'fy',
140 | 'gl',
141 | 'ka',
142 | 'de',
143 | 'el',
144 | 'gu',
145 | 'ht',
146 | 'ha',
147 | 'haw',
148 | 'iw',
149 | 'hi',
150 | 'hmn',
151 | 'hu',
152 | 'is',
153 | 'ig',
154 | 'id',
155 | 'ga',
156 | 'it',
157 | 'ja',
158 | 'jw',
159 | 'kn',
160 | 'kk',
161 | 'km',
162 | 'ko',
163 | 'ku',
164 | 'ky',
165 | 'lo',
166 | 'la',
167 | 'lv',
168 | 'lt',
169 | 'lb',
170 | 'mk',
171 | 'mg',
172 | 'ms',
173 | 'ml',
174 | 'mt',
175 | 'mi',
176 | 'mr',
177 | 'mn',
178 | 'my',
179 | 'ne',
180 | 'no',
181 | 'ny',
182 | 'ps',
183 | 'fa',
184 | 'pl',
185 | 'pt',
186 | 'pa',
187 | 'ro',
188 | 'ru',
189 | 'sm',
190 | 'gd',
191 | 'sr',
192 | 'st',
193 | 'sn',
194 | 'sd',
195 | 'si',
196 | 'sk',
197 | 'sl',
198 | 'so',
199 | 'es',
200 | 'su',
201 | 'sw',
202 | 'sv',
203 | 'tl',
204 | 'tg',
205 | 'ta',
206 | 'te',
207 | 'th',
208 | 'tr',
209 | 'uk',
210 | 'ur',
211 | 'uz',
212 | 'vi',
213 | 'cy',
214 | 'xh',
215 | 'yi',
216 | 'yo',
217 | 'zu'
218 | ];
219 |
220 |
221 | Translator.prototype.translateSingleText = function (context) {
222 | if (!checkCount(context)) {
223 | return;
224 | } else {
225 | if (!checkTextLayerType(context)) {
226 | return;
227 | } else {
228 | var dialog = this.buildDialog(context);
229 | var languageIndex = handleAlertResponse(dialog, dialog.runModal());
230 |
231 | if (languageIndex == null) {
232 | return;
233 | }
234 |
235 | var textLayer = context.selection[0];
236 | var baseLanguage = detectLenguage(textLayer.stringValue());
237 |
238 | if (!baseLanguage) {
239 | return;
240 | }
241 |
242 | var toLanguage = this.languageCodes[languageIndex];
243 |
244 | if (!toLanguage) {
245 | return;
246 | }
247 |
248 | if (baseLanguage == toLanguage) {
249 | context.document.showMessage('Please select a different language');
250 | }
251 |
252 | textLayer.setStringValue(getSingleTranslation(textLayer.stringValue(), baseLanguage, toLanguage));
253 | }
254 | }
255 | }
256 |
257 | Translator.prototype.translateArtboard = function (context) {
258 | if (!checkCount(context)) {
259 | return;
260 | } else {
261 | if (!checkArtboardLayerType(context)) {
262 | return;
263 | } else {
264 | var dialog = this.buildDialog(context);
265 | var languageIndex = handleAlertResponse(dialog, dialog.runModal());
266 |
267 | if (languageIndex == null) {
268 | return;
269 | }
270 |
271 | var artboardCopy = context.selection[0].duplicate();
272 | artboardCopy.frame().x = artboardCopy.frame().x() + context.selection[0].frame().width() + 100;
273 |
274 | if (MSApplicationMetadata.metadata().appVersion > 45) {
275 | artboardCopy.select_byExpandingSelection(true, false);
276 | } else {
277 | artboardCopy.select_byExtendingSelection(true, false);
278 | }
279 |
280 | var textLayers = selectLayersOfTypeInContainer(context.document, "MSTextLayer", artboardCopy);
281 | var toLanguage = this.languageCodes[languageIndex];
282 |
283 | for (var x = 0, l = textLayers.length; x < l; x++) {
284 | var textLayer = textLayers[x];
285 | var baseLanguage = detectLenguage(textLayer.stringValue());
286 |
287 | if(!baseLanguage) {
288 | return;
289 | }
290 |
291 | textLayer.setStringValue(getSingleTranslation(textLayer.stringValue(), baseLanguage, toLanguage));
292 | }
293 | }
294 | }
295 | }
296 |
297 |
298 | Translator.prototype.translateEverything = function (context) {
299 | var doc = context.document;
300 | var initialPage = [doc currentPage];
301 | var artboards = [initialPage artboards];
302 |
303 | if (artboards.length === 0) {
304 | return;
305 | }
306 |
307 | var dialog = this.buildDialog(context);
308 | var languageIndex = handleAlertResponse(dialog, dialog.runModal());
309 |
310 | if (languageIndex == null) {
311 | return;
312 | }
313 |
314 | var newPage = duplicatePage(context, this.languageLabels[languageIndex]);
315 | var artboards = selectLayersOfTypeInContainer(context.document, "MSArtboardGroup", newPage);
316 |
317 | for (var x = artboards.length - 1; x >= 0; x--) {
318 | var artboardCopy = artboards[x];
319 |
320 | var textLayers = selectLayersOfTypeInContainer(context.document, "MSTextLayer", artboardCopy);
321 | var toLanguage = this.languageCodes[languageIndex];
322 |
323 | for (var x = 0, l = textLayers.length; x < l; x++) {
324 | var textLayer = textLayers[x];
325 | var baseLanguage = detectLenguage(textLayer.stringValue());
326 |
327 | if(!baseLanguage) {
328 | return;
329 | }
330 |
331 | textLayer.setStringValue(getSingleTranslation(textLayer.stringValue(), baseLanguage, toLanguage));
332 | }
333 | }
334 | }
335 |
336 |
337 | Translator.prototype.buildDialog = function (context) {
338 | var apiKey = getOption('apiKey', '');
339 | var dialogWindow = COSAlertWindow.new();
340 | var informativeText = '';
341 |
342 | if (apiKey.length == 0) {
343 | informativeText = 'You have to set your Google API Key into the plugin settings (Plugins > Translate.me > Set Google API Key...)';
344 | } else {
345 | informativeText = 'Please select the language in which you want to translate the text:';
346 | }
347 |
348 | dialogWindow.setMessageText('Translate.me');
349 | dialogWindow.setInformativeText(informativeText);
350 |
351 |
352 | if (apiKey.length == 0) {
353 | var link = NSButton.alloc().initWithFrame(NSMakeRect(0, 0, 200, 20)));
354 | link.setTitle('How to get a Google API Key');
355 | link.setBezelStyle(NSInlineBezelStyle);
356 |
357 | link.setCOSJSTargetFunction(function() {
358 | var url = NSURL.URLWithString(@"https://github.com/eddiesigner/sketch-translate-me/wiki/Generate-a-Google-API-Key");
359 |
360 | if (!NSWorkspace.sharedWorkspace().openURL(url)) {
361 | log(@"Failed to open url:" + url.description());
362 | }
363 | });
364 |
365 | dialogWindow.addAccessoryView(link);
366 | } else {
367 | var languageSelect = createSelect(this.languageLabels);
368 | dialogWindow.addAccessoryView(languageSelect);
369 |
370 | dialogWindow.addButtonWithTitle('OK');
371 | dialogWindow.addButtonWithTitle('Cancel');
372 | }
373 |
374 | dialogWindow.setIcon(NSImage.alloc().initByReferencingFile(context.plugin.urlForResourceNamed("logo@2x.png").path()));
375 |
376 | return dialogWindow;
377 | }
378 |
379 |
380 | Translator.prototype.openApiKeyWindow = function (context) {
381 | var dialog = this.buildKeyWindow(context);
382 | var response = handleKeyAlertResponse(dialog, dialog.runModal());
383 | }
384 |
385 |
386 | Translator.prototype.buildKeyWindow = function (context) {
387 | var apiKey = getOption('apiKey', '');
388 | var dialogWindow = COSAlertWindow.new();
389 |
390 | dialogWindow.setMessageText('Translate.me');
391 | dialogWindow.setInformativeText('Paste here your Google API Key (you have to do this just once):');
392 |
393 | dialogWindow.addTextFieldWithValue(apiKey.length == 0 ? '' : getOption('apiKey'));
394 |
395 | var apiKeyTextBox = dialogWindow.viewAtIndex(0);
396 |
397 | dialogWindow.alert().window().setInitialFirstResponder(apiKeyTextBox);
398 |
399 | dialogWindow.addButtonWithTitle('OK');
400 | dialogWindow.addButtonWithTitle('Cancel');
401 |
402 | dialogWindow.setIcon(NSImage.alloc().initByReferencingFile(context.plugin.urlForResourceNamed("logo@2x.png").path()));
403 |
404 | return dialogWindow;
405 | }
--------------------------------------------------------------------------------