2 * "$Id: translate.c 6921 2007-09-06 13:38:37Z mike $"
4 * HTTP-based translation program for the Common UNIX Printing System (CUPS).
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.)
10 * Copyright 2007 by Apple Inc.
11 * Copyright 1997-2006 by Easy Software Products.
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/".
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.
28 * Include necessary headers...
31 #include <cups/string.h>
32 #include <cups/file.h>
33 #include <cups/http.h>
34 #include <cups/i18n.h>
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
);
49 * 'main()' - Main entry.
52 int /* O - Exit status */
53 main(int argc
, /* I - Number of command-line arguments */
54 char *argv
[]) /* I - Command-line arguments */
56 cups_array_t
*cat
; /* Message catalog */
61 fputs("Usage: translate cups_language.po language\n", stderr
);
65 if (access(argv
[1], 0))
66 cat
= _cupsMessageLoad("cups.pot");
68 cat
= _cupsMessageLoad(argv
[1]);
72 puts("Unable to load message catalog.");
76 if (!translate_messages(cat
, argv
[2]))
78 puts("Unable to translate message catalog.");
82 if (!save_messages(cat
, argv
[1]))
84 puts("Unable to save message catalog.");
93 * 'save_messages()' - Save messages to a .po file.
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 */
100 _cups_message_t
*m
; /* Current message */
101 cups_file_t
*fp
; /* File pointer */
105 * Open the message catalog...
108 if ((fp
= cupsFileOpen(filename
, "w")) == NULL
)
112 * Save the messages to a file...
115 for (m
= (_cups_message_t
*)cupsArrayFirst(cat
);
117 m
= (_cups_message_t
*)cupsArrayNext(cat
))
119 if (cupsFilePuts(fp
, "msgid \"") < 0)
122 if (!write_string(fp
, m
->id
))
125 if (cupsFilePuts(fp
, "\"\nmsgstr \"") < 0)
130 if (!write_string(fp
, m
->str
))
134 if (cupsFilePuts(fp
, "\"\n") < 0)
145 * 'translate_messages()' - Translate messages using Google.
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... */
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.
158 * Translation requests are sent as HTTP POSTs to
159 * "http://translate.google.com/translate_t" with the following form
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
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 */
185 * Connect to translate.google.com...
188 puts("Connecting to translate.google.com...");
190 if ((http
= httpConnect("translate.google.com", 80)) == NULL
)
192 perror("Unable to connect to translate.google.com");
197 * Scan the current messages, requesting a translation of any untranslated
201 for (m
= (_cups_message_t
*)cupsArrayFirst(cat
), ret
= 1;
203 m
= (_cups_message_t
*)cupsArrayNext(cat
))
206 * Skip messages that are already translated...
209 if (m
->str
&& m
->str
[0])
213 * Encode the form data into the buffer...
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;
221 for (idptr
= m
->id
; *idptr
&& bufptr
< bufend
; idptr
++)
224 else if (*idptr
< ' ' || *idptr
== '%')
226 sprintf(bufptr
, "%%%02X", *idptr
& 255);
229 else if (*idptr
!= '&')
235 sprintf(length
, "%d", (int)(bufptr
- buffer
));
238 * Send the request...
241 printf("\"%s\" = ", m
->id
);
248 httpClearFields(http
);
249 httpSetField(http
, HTTP_FIELD_CONTENT_TYPE
,
250 "application/x-www-form-urlencoded");
251 httpSetField(http
, HTTP_FIELD_CONTENT_LENGTH
, length
);
253 if (httpPost(http
, "/translate_t"))
256 httpPost(http
, "/translate_t");
259 httpWrite2(http
, buffer
, bufptr
- buffer
);
261 while ((status
= httpUpdate(http
)) == HTTP_CONTINUE
);
263 if (status
!= HTTP_OK
&& status
!= HTTP_ERROR
)
268 while (status
== HTTP_ERROR
&& tries
< 10);
270 if (status
== HTTP_OK
)
273 * OK, read the translation back...
277 bufend
= buffer
+ sizeof(buffer
) - 1;
279 while ((bytes
= httpRead2(http
, bufptr
, bufend
- bufptr
)) > 0)
296 * Find the first textarea element - that will have the translation data...
299 if ((bufptr
= strstr(buffer
, "<textarea")) == NULL
)
302 * No textarea, abort!
305 puts("NO TEXTAREA!");
310 if ((bufptr
= strchr(bufptr
, '>')) == NULL
)
313 * textarea doesn't end, abort!
316 puts("TEXTAREA SHORT DATA!");
323 if ((bufend
= strstr(bufptr
, "</textarea>")) == NULL
)
326 * textarea doesn't close, abort!
329 puts("/TEXTAREA SHORT DATA!");
337 * Copy the translation...
340 m
->str
= strdup(bufptr
);
343 * Convert character entities to regular chars...
346 for (bufptr
= strchr(m
->str
, '&');
348 bufptr
= strchr(bufptr
+ 1, '&'))
350 if (!strncmp(bufptr
, "<", 4))
353 _cups_strcpy(bufptr
+ 1, bufptr
+ 4);
355 else if (!strncmp(bufptr
, ">", 4))
358 _cups_strcpy(bufptr
+ 1, bufptr
+ 4);
360 else if (!strncmp(bufptr
, "&", 5))
361 _cups_strcpy(bufptr
+ 1, bufptr
+ 5);
364 printf("\"%s\"\n", m
->str
);
366 else if (status
== HTTP_ERROR
)
368 printf("NETWORK ERROR (%s)!\n", strerror(httpError(http
)));
374 printf("HTTP ERROR %d!\n", status
);
387 * 'write_string()' - Write a quoted string to a file.
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 */
399 if (cupsFilePuts(fp
, "\\n") < 0)
404 if (cupsFilePuts(fp
, "\\r") < 0)
409 if (cupsFilePuts(fp
, "\\t") < 0)
414 if (cupsFilePuts(fp
, "\\\\") < 0)
419 if (cupsFilePuts(fp
, "\\\"") < 0)
424 if ((*s
& 255) < ' ')
426 if (cupsFilePrintf(fp
, "\\%o", *s
) < 0)
429 else if (cupsFilePutChar(fp
, *s
) < 0)
442 * End of "$Id: translate.c 6921 2007-09-06 13:38:37Z mike $".