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