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)