]> git.ipfire.org Git - thirdparty/cups.git/blame - locale/translate.c
Fix clang-reported issues (<rdar://problem/15936066>)
[thirdparty/cups.git] / locale / translate.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
71e16022 4 * HTTP-based translation program for CUPS.
ef416fc2 5 *
6 * This program uses Google to translate the CUPS template (cups.pot) to
7 * several different languages. The translation isn't perfect, but it's
8 * a start (better than working from scratch.)
9 *
71e16022 10 * Copyright 2007-2010 by Apple Inc.
ef416fc2 11 * Copyright 1997-2006 by Easy Software Products.
12 *
13 * These coded instructions, statements, and computer programs are the
bc44d920 14 * property of Apple Inc. and are protected by Federal copyright
15 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
16 * which should have been included with this file. If this file is
17 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 18 *
19 * Contents:
20 *
e1d6a774 21 * main() - Main entry.
22 * save_messages() - Save messages to a .po file.
23 * translate_messages() - Translate messages using Google.
24 * write_string() - Write a quoted string to a file.
ef416fc2 25 */
26
27/*
28 * Include necessary headers...
29 */
30
71e16022 31#include <cups/cups-private.h>
ef416fc2 32#include <unistd.h>
33
34
35/*
36 * Local functions...
37 */
38
39int save_messages(cups_array_t *cat, const char *filename);
40int translate_messages(cups_array_t *cat, const char *lang);
41int write_string(cups_file_t *fp, const char *s);
42
43
44/*
45 * 'main()' - Main entry.
46 */
47
48int /* O - Exit status */
49main(int argc, /* I - Number of command-line arguments */
50 char *argv[]) /* I - Command-line arguments */
51{
52 cups_array_t *cat; /* Message catalog */
53
54
55 if (argc != 3)
56 {
57 fputs("Usage: translate cups_language.po language\n", stderr);
58 return (1);
59 }
60
61 if (access(argv[1], 0))
8b116e60 62 cat = _cupsMessageLoad("cups.pot", 1);
ef416fc2 63 else
8b116e60 64 cat = _cupsMessageLoad(argv[1], 1);
ef416fc2 65
66 if (!cat)
67 {
68 puts("Unable to load message catalog.");
69 return (1);
70 }
71
72 if (!translate_messages(cat, argv[2]))
73 {
74 puts("Unable to translate message catalog.");
75 return (1);
76 }
77
78 if (!save_messages(cat, argv[1]))
79 {
80 puts("Unable to save message catalog.");
81 return (1);
82 }
83
84 return (0);
85}
86
87
88/*
89 * 'save_messages()' - Save messages to a .po file.
90 */
91
92int /* O - 1 on success, 0 on error */
93save_messages(cups_array_t *cat, /* I - Message catalog */
94 const char *filename) /* I - File to save to */
95{
96 _cups_message_t *m; /* Current message */
97 cups_file_t *fp; /* File pointer */
98
99
100 /*
101 * Open the message catalog...
102 */
103
104 if ((fp = cupsFileOpen(filename, "w")) == NULL)
105 return (0);
106
107 /*
108 * Save the messages to a file...
109 */
110
111 for (m = (_cups_message_t *)cupsArrayFirst(cat);
112 m;
113 m = (_cups_message_t *)cupsArrayNext(cat))
114 {
115 if (cupsFilePuts(fp, "msgid \"") < 0)
116 break;
117
118 if (!write_string(fp, m->id))
119 break;
120
121 if (cupsFilePuts(fp, "\"\nmsgstr \"") < 0)
122 break;
123
124 if (m->str)
125 {
126 if (!write_string(fp, m->str))
127 break;
128 }
129
130 if (cupsFilePuts(fp, "\"\n") < 0)
131 break;
132 }
133
134 cupsFileClose(fp);
135
136 return (!m);
137}
138
139
140/*
141 * 'translate_messages()' - Translate messages using Google.
142 */
143
144int /* O - 1 on success, 0 on error */
145translate_messages(cups_array_t *cat, /* I - Message catalog */
146 const char *lang) /* I - Output language... */
147{
148 /*
149 * Google provides a simple translation/language tool for translating
150 * from one language to another. It is far from perfect, however it
151 * can be used to get a basic translation done or update an existing
152 * translation when no other resources are available.
153 *
154 * Translation requests are sent as HTTP POSTs to
155 * "http://translate.google.com/translate_t" with the following form
156 * variables:
157 *
158 * Name Description Value
159 * -------- ---------------------------------- ----------------
160 * hl Help language? "en"
161 * ie Input encoding "UTF8"
162 * langpair Language pair "en|" + language
163 * oe Output encoding "UTF8"
164 * text Text to translate translation string
165 */
166
167 int ret; /* Return value */
168 _cups_message_t *m; /* Current message */
169 int tries; /* Number of tries... */
170 http_t *http; /* HTTP connection */
171 http_status_t status; /* Status of POST request */
172 char *idptr, /* Pointer into msgid */
173 buffer[65536], /* Input/output buffer */
174 *bufptr, /* Pointer into buffer */
175 *bufend, /* Pointer to end of buffer */
176 length[16]; /* Content length */
177 int bytes; /* Number of bytes read */
178
179
180 /*
181 * Connect to translate.google.com...
182 */
183
184 puts("Connecting to translate.google.com...");
185
186 if ((http = httpConnect("translate.google.com", 80)) == NULL)
187 {
188 perror("Unable to connect to translate.google.com");
189 return (0);
190 }
191
192 /*
193 * Scan the current messages, requesting a translation of any untranslated
194 * messages...
195 */
196
197 for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1;
198 m;
199 m = (_cups_message_t *)cupsArrayNext(cat))
200 {
201 /*
202 * Skip messages that are already translated...
203 */
204
205 if (m->str && m->str[0])
206 continue;
207
208 /*
209 * Encode the form data into the buffer...
210 */
211
212 snprintf(buffer, sizeof(buffer),
213 "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang);
214 bufptr = buffer + strlen(buffer);
215 bufend = buffer + sizeof(buffer) - 5;
216
217 for (idptr = m->id; *idptr && bufptr < bufend; idptr ++)
218 if (*idptr == ' ')
219 *bufptr++ = '+';
220 else if (*idptr < ' ' || *idptr == '%')
221 {
222 sprintf(bufptr, "%%%02X", *idptr & 255);
223 bufptr += 3;
224 }
225 else if (*idptr != '&')
226 *bufptr++ = *idptr;
227
228 *bufptr++ = '&';
229 *bufptr = '\0';
230
e1d6a774 231 sprintf(length, "%d", (int)(bufptr - buffer));
ef416fc2 232
233 /*
234 * Send the request...
235 */
236
237 printf("\"%s\" = ", m->id);
238 fflush(stdout);
239
240 tries = 0;
241
242 do
243 {
244 httpClearFields(http);
245 httpSetField(http, HTTP_FIELD_CONTENT_TYPE,
246 "application/x-www-form-urlencoded");
247 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length);
248
249 if (httpPost(http, "/translate_t"))
250 {
251 httpReconnect(http);
252 httpPost(http, "/translate_t");
253 }
254
a4d04587 255 httpWrite2(http, buffer, bufptr - buffer);
ef416fc2 256
257 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
258
259 if (status != HTTP_OK && status != HTTP_ERROR)
260 httpFlush(http);
261
262 tries ++;
263 }
264 while (status == HTTP_ERROR && tries < 10);
265
266 if (status == HTTP_OK)
267 {
268 /*
269 * OK, read the translation back...
270 */
271
272 bufptr = buffer;
273 bufend = buffer + sizeof(buffer) - 1;
274
a4d04587 275 while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0)
ef416fc2 276 bufptr += bytes;
277
278 if (bytes < 0)
279 {
280 /*
281 * Read error, abort!
282 */
283
284 puts("READ ERROR!");
285 ret = 0;
286 break;
287 }
288
289 *bufptr = '\0';
290
291 /*
49d87452 292 * Find the div containing translation
ef416fc2 293 */
294
49d87452 295 if ((bufptr = strstr(buffer, "<div id=result_box")) == NULL)
ef416fc2 296 {
297 /*
298 * No textarea, abort!
299 */
300
49d87452 301 puts("NO div id=result_box!");
ef416fc2 302 ret = 0;
303 break;
304 }
305
306 if ((bufptr = strchr(bufptr, '>')) == NULL)
307 {
308 /*
309 * textarea doesn't end, abort!
310 */
311
49d87452 312 puts("DIV SHORT DATA!");
ef416fc2 313 ret = 0;
314 break;
315 }
316
317 bufptr ++;
318
49d87452 319 if ((bufend = strstr(bufptr, "</div>")) == NULL)
ef416fc2 320 {
321 /*
322 * textarea doesn't close, abort!
323 */
324
49d87452 325 puts("/DIV SHORT DATA!");
ef416fc2 326 ret = 0;
327 break;
328 }
329
330 *bufend = '\0';
331
332 /*
333 * Copy the translation...
334 */
335
336 m->str = strdup(bufptr);
337
338 /*
339 * Convert character entities to regular chars...
340 */
341
342 for (bufptr = strchr(m->str, '&');
343 bufptr;
344 bufptr = strchr(bufptr + 1, '&'))
345 {
346 if (!strncmp(bufptr, "&lt;", 4))
347 {
348 *bufptr = '<';
349 _cups_strcpy(bufptr + 1, bufptr + 4);
350 }
351 else if (!strncmp(bufptr, "&gt;", 4))
352 {
353 *bufptr = '>';
354 _cups_strcpy(bufptr + 1, bufptr + 4);
355 }
356 else if (!strncmp(bufptr, "&amp;", 5))
357 _cups_strcpy(bufptr + 1, bufptr + 5);
358 }
359
360 printf("\"%s\"\n", m->str);
361 }
362 else if (status == HTTP_ERROR)
363 {
364 printf("NETWORK ERROR (%s)!\n", strerror(httpError(http)));
365 ret = 0;
366 break;
367 }
368 else
369 {
370 printf("HTTP ERROR %d!\n", status);
371 ret = 0;
372 break;
373 }
374 }
375
376 httpClose(http);
377
378 return (ret);
379}
380
381
382/*
383 * 'write_string()' - Write a quoted string to a file.
384 */
385
386int /* O - 1 on success, 0 on failure */
387write_string(cups_file_t *fp, /* I - File to write to */
388 const char *s) /* I - String */
389{
390 while (*s)
391 {
392 switch (*s)
393 {
394 case '\n' :
395 if (cupsFilePuts(fp, "\\n") < 0)
396 return (0);
397 break;
398
399 case '\r' :
400 if (cupsFilePuts(fp, "\\r") < 0)
401 return (0);
402 break;
403
404 case '\t' :
405 if (cupsFilePuts(fp, "\\t") < 0)
406 return (0);
407 break;
408
409 case '\\' :
410 if (cupsFilePuts(fp, "\\\\") < 0)
411 return (0);
412 break;
413
414 case '\"' :
415 if (cupsFilePuts(fp, "\\\"") < 0)
416 return (0);
417 break;
418
419 default :
420 if ((*s & 255) < ' ')
421 {
422 if (cupsFilePrintf(fp, "\\%o", *s) < 0)
423 return (0);
424 }
425 else if (cupsFilePutChar(fp, *s) < 0)
426 return (0);
427 break;
428 }
429
430 s ++;
431 }
432
433 return (1);
434}
435
436
437/*
f2d18633 438 * End of "$Id$".
ef416fc2 439 */