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