2 * "$Id: translate.c 9048 2010-03-24 08:07:15Z mike $"
4 * HTTP-based translation program for 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-2010 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/cups-private.h>
39 int save_messages(cups_array_t *cat, const char *filename);
40 int translate_messages(cups_array_t *cat, const char *lang);
41 int write_string(cups_file_t *fp, const char *s);
45 * 'main()' - Main entry.
48 int /* O - Exit status */
49 main(int argc, /* I - Number of command-line arguments */
50 char *argv[]) /* I - Command-line arguments */
52 cups_array_t *cat; /* Message catalog */
57 fputs("Usage: translate cups_language.po language\n", stderr);
61 if (access(argv[1], 0))
62 cat = _cupsMessageLoad("cups.pot", 1);
64 cat = _cupsMessageLoad(argv[1], 1);
68 puts("Unable to load message catalog.");
72 if (!translate_messages(cat, argv[2]))
74 puts("Unable to translate message catalog.");
78 if (!save_messages(cat, argv[1]))
80 puts("Unable to save message catalog.");
89 * 'save_messages()' - Save messages to a .po file.
92 int /* O - 1 on success, 0 on error */
93 save_messages(cups_array_t *cat, /* I - Message catalog */
94 const char *filename) /* I - File to save to */
96 _cups_message_t *m; /* Current message */
97 cups_file_t *fp; /* File pointer */
101 * Open the message catalog...
104 if ((fp = cupsFileOpen(filename, "w")) == NULL)
108 * Save the messages to a file...
111 for (m = (_cups_message_t *)cupsArrayFirst(cat);
113 m = (_cups_message_t *)cupsArrayNext(cat))
115 if (cupsFilePuts(fp, "msgid \"") < 0)
118 if (!write_string(fp, m->id))
121 if (cupsFilePuts(fp, "\"\nmsgstr \"") < 0)
126 if (!write_string(fp, m->str))
130 if (cupsFilePuts(fp, "\"\n") < 0)
141 * 'translate_messages()' - Translate messages using Google.
144 int /* O - 1 on success, 0 on error */
145 translate_messages(cups_array_t *cat, /* I - Message catalog */
146 const char *lang) /* I - Output language... */
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.
154 * Translation requests are sent as HTTP POSTs to
155 * "http://translate.google.com/translate_t" with the following form
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
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 */
181 * Connect to translate.google.com...
184 puts("Connecting to translate.google.com...");
186 if ((http = httpConnect("translate.google.com", 80)) == NULL)
188 perror("Unable to connect to translate.google.com");
193 * Scan the current messages, requesting a translation of any untranslated
197 for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1;
199 m = (_cups_message_t *)cupsArrayNext(cat))
202 * Skip messages that are already translated...
205 if (m->str && m->str[0])
209 * Encode the form data into the buffer...
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;
217 for (idptr = m->id; *idptr && bufptr < bufend; idptr ++)
220 else if (*idptr < ' ' || *idptr == '%')
222 sprintf(bufptr, "%%%02X", *idptr & 255);
225 else if (*idptr != '&')
231 sprintf(length, "%d", (int)(bufptr - buffer));
234 * Send the request...
237 printf("\"%s\" = ", m->id);
244 httpClearFields(http);
245 httpSetField(http, HTTP_FIELD_CONTENT_TYPE,
246 "application/x-www-form-urlencoded");
247 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length);
249 if (httpPost(http, "/translate_t"))
252 httpPost(http, "/translate_t");
255 httpWrite2(http, buffer, bufptr - buffer);
257 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
259 if (status != HTTP_OK && status != HTTP_ERROR)
264 while (status == HTTP_ERROR && tries < 10);
266 if (status == HTTP_OK)
269 * OK, read the translation back...
273 bufend = buffer + sizeof(buffer) - 1;
275 while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0)
292 * Find the div containing translation
295 if ((bufptr = strstr(buffer, "<div id=result_box")) == NULL)
298 * No textarea, abort!
301 puts("NO div id=result_box!");
306 if ((bufptr = strchr(bufptr, '>')) == NULL)
309 * textarea doesn't end, abort!
312 puts("DIV SHORT DATA!");
319 if ((bufend = strstr(bufptr, "</div>")) == NULL)
322 * textarea doesn't close, abort!
325 puts("/DIV SHORT DATA!");
333 * Copy the translation...
336 m->str = strdup(bufptr);
339 * Convert character entities to regular chars...
342 for (bufptr = strchr(m->str, '&');
344 bufptr = strchr(bufptr + 1, '&'))
346 if (!strncmp(bufptr, "<", 4))
349 _cups_strcpy(bufptr + 1, bufptr + 4);
351 else if (!strncmp(bufptr, ">", 4))
354 _cups_strcpy(bufptr + 1, bufptr + 4);
356 else if (!strncmp(bufptr, "&", 5))
357 _cups_strcpy(bufptr + 1, bufptr + 5);
360 printf("\"%s\"\n", m->str);
362 else if (status == HTTP_ERROR)
364 printf("NETWORK ERROR (%s)!\n", strerror(httpError(http)));
370 printf("HTTP ERROR %d!\n", status);
383 * 'write_string()' - Write a quoted string to a file.
386 int /* O - 1 on success, 0 on failure */
387 write_string(cups_file_t *fp, /* I - File to write to */
388 const char *s) /* I - String */
395 if (cupsFilePuts(fp, "\\n") < 0)
400 if (cupsFilePuts(fp, "\\r") < 0)
405 if (cupsFilePuts(fp, "\\t") < 0)
410 if (cupsFilePuts(fp, "\\\\") < 0)
415 if (cupsFilePuts(fp, "\\\"") < 0)
420 if ((*s & 255) < ' ')
422 if (cupsFilePrintf(fp, "\\%o", *s) < 0)
425 else if (cupsFilePutChar(fp, *s) < 0)
438 * End of "$Id: translate.c 9048 2010-03-24 08:07:15Z mike $".