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