2 * "$Id: translate.c 5023 2006-01-29 14:39:44Z 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 1997-2006 by Easy Software Products.
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
19 * Attn: CUPS Licensing Information
20 * Easy Software Products
21 * 44145 Airport View Drive, Suite 204
22 * Hollywood, Maryland 20636 USA
24 * Voice: (301) 373-9600
25 * EMail: cups-info@cups.org
26 * WWW: http://www.cups.org
33 * Include necessary headers...
36 #include <cups/string.h>
37 #include <cups/file.h>
38 #include <cups/http.h>
39 #include <cups/i18n.h>
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
);
54 * 'main()' - Main entry.
57 int /* O - Exit status */
58 main(int argc
, /* I - Number of command-line arguments */
59 char *argv
[]) /* I - Command-line arguments */
61 cups_array_t
*cat
; /* Message catalog */
66 fputs("Usage: translate cups_language.po language\n", stderr
);
70 if (access(argv
[1], 0))
71 cat
= _cupsMessageLoad("cups.pot");
73 cat
= _cupsMessageLoad(argv
[1]);
77 puts("Unable to load message catalog.");
81 if (!translate_messages(cat
, argv
[2]))
83 puts("Unable to translate message catalog.");
87 if (!save_messages(cat
, argv
[1]))
89 puts("Unable to save message catalog.");
98 * 'save_messages()' - Save messages to a .po file.
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 */
105 _cups_message_t
*m
; /* Current message */
106 cups_file_t
*fp
; /* File pointer */
110 * Open the message catalog...
113 if ((fp
= cupsFileOpen(filename
, "w")) == NULL
)
117 * Save the messages to a file...
120 for (m
= (_cups_message_t
*)cupsArrayFirst(cat
);
122 m
= (_cups_message_t
*)cupsArrayNext(cat
))
124 if (cupsFilePuts(fp
, "msgid \"") < 0)
127 if (!write_string(fp
, m
->id
))
130 if (cupsFilePuts(fp
, "\"\nmsgstr \"") < 0)
135 if (!write_string(fp
, m
->str
))
139 if (cupsFilePuts(fp
, "\"\n") < 0)
150 * 'translate_messages()' - Translate messages using Google.
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... */
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.
163 * Translation requests are sent as HTTP POSTs to
164 * "http://translate.google.com/translate_t" with the following form
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
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 */
190 * Connect to translate.google.com...
193 puts("Connecting to translate.google.com...");
195 if ((http
= httpConnect("translate.google.com", 80)) == NULL
)
197 perror("Unable to connect to translate.google.com");
202 * Scan the current messages, requesting a translation of any untranslated
206 for (m
= (_cups_message_t
*)cupsArrayFirst(cat
), ret
= 1;
208 m
= (_cups_message_t
*)cupsArrayNext(cat
))
211 * Skip messages that are already translated...
214 if (m
->str
&& m
->str
[0])
218 * Encode the form data into the buffer...
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;
226 for (idptr
= m
->id
; *idptr
&& bufptr
< bufend
; idptr
++)
229 else if (*idptr
< ' ' || *idptr
== '%')
231 sprintf(bufptr
, "%%%02X", *idptr
& 255);
234 else if (*idptr
!= '&')
240 sprintf(length
, "%d", bufptr
- buffer
);
243 * Send the request...
246 printf("\"%s\" = ", m
->id
);
253 httpClearFields(http
);
254 httpSetField(http
, HTTP_FIELD_CONTENT_TYPE
,
255 "application/x-www-form-urlencoded");
256 httpSetField(http
, HTTP_FIELD_CONTENT_LENGTH
, length
);
258 if (httpPost(http
, "/translate_t"))
261 httpPost(http
, "/translate_t");
264 httpWrite2(http
, buffer
, bufptr
- buffer
);
266 while ((status
= httpUpdate(http
)) == HTTP_CONTINUE
);
268 if (status
!= HTTP_OK
&& status
!= HTTP_ERROR
)
273 while (status
== HTTP_ERROR
&& tries
< 10);
275 if (status
== HTTP_OK
)
278 * OK, read the translation back...
282 bufend
= buffer
+ sizeof(buffer
) - 1;
284 while ((bytes
= httpRead2(http
, bufptr
, bufend
- bufptr
)) > 0)
301 * Find the first textarea element - that will have the translation data...
304 if ((bufptr
= strstr(buffer
, "<textarea")) == NULL
)
307 * No textarea, abort!
310 puts("NO TEXTAREA!");
315 if ((bufptr
= strchr(bufptr
, '>')) == NULL
)
318 * textarea doesn't end, abort!
321 puts("TEXTAREA SHORT DATA!");
328 if ((bufend
= strstr(bufptr
, "</textarea>")) == NULL
)
331 * textarea doesn't close, abort!
334 puts("/TEXTAREA SHORT DATA!");
342 * Copy the translation...
345 m
->str
= strdup(bufptr
);
348 * Convert character entities to regular chars...
351 for (bufptr
= strchr(m
->str
, '&');
353 bufptr
= strchr(bufptr
+ 1, '&'))
355 if (!strncmp(bufptr
, "<", 4))
358 _cups_strcpy(bufptr
+ 1, bufptr
+ 4);
360 else if (!strncmp(bufptr
, ">", 4))
363 _cups_strcpy(bufptr
+ 1, bufptr
+ 4);
365 else if (!strncmp(bufptr
, "&", 5))
366 _cups_strcpy(bufptr
+ 1, bufptr
+ 5);
369 printf("\"%s\"\n", m
->str
);
371 else if (status
== HTTP_ERROR
)
373 printf("NETWORK ERROR (%s)!\n", strerror(httpError(http
)));
379 printf("HTTP ERROR %d!\n", status
);
392 * 'write_string()' - Write a quoted string to a file.
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 */
404 if (cupsFilePuts(fp
, "\\n") < 0)
409 if (cupsFilePuts(fp
, "\\r") < 0)
414 if (cupsFilePuts(fp
, "\\t") < 0)
419 if (cupsFilePuts(fp
, "\\\\") < 0)
424 if (cupsFilePuts(fp
, "\\\"") < 0)
429 if ((*s
& 255) < ' ')
431 if (cupsFilePrintf(fp
, "\\%o", *s
) < 0)
434 else if (cupsFilePutChar(fp
, *s
) < 0)
447 * End of "$Id: translate.c 5023 2006-01-29 14:39:44Z mike $".