| /* |
| * "$Id: translate.c 6921 2007-09-06 13:38:37Z mike $" |
| * |
| * HTTP-based translation program for the Common UNIX Printing System (CUPS). |
| * |
| * This program uses Google to translate the CUPS template (cups.pot) to |
| * several different languages. The translation isn't perfect, but it's |
| * a start (better than working from scratch.) |
| * |
| * Copyright 2007 by Apple Inc. |
| * Copyright 1997-2006 by Easy Software Products. |
| * |
| * These coded instructions, statements, and computer programs are the |
| * property of Apple Inc. and are protected by Federal copyright |
| * law. Distribution and use rights are outlined in the file "LICENSE.txt" |
| * which should have been included with this file. If this file is |
| * file is missing or damaged, see the license at "http://www.cups.org/". |
| * |
| * Contents: |
| * |
| * main() - Main entry. |
| * save_messages() - Save messages to a .po file. |
| * translate_messages() - Translate messages using Google. |
| * write_string() - Write a quoted string to a file. |
| */ |
| |
| /* |
| * Include necessary headers... |
| */ |
| |
| #include <cups/string.h> |
| #include <cups/file.h> |
| #include <cups/http.h> |
| #include <cups/i18n.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| |
| /* |
| * Local functions... |
| */ |
| |
| int save_messages(cups_array_t *cat, const char *filename); |
| int translate_messages(cups_array_t *cat, const char *lang); |
| int write_string(cups_file_t *fp, const char *s); |
| |
| |
| /* |
| * 'main()' - Main entry. |
| */ |
| |
| int /* O - Exit status */ |
| main(int argc, /* I - Number of command-line arguments */ |
| char *argv[]) /* I - Command-line arguments */ |
| { |
| cups_array_t *cat; /* Message catalog */ |
| |
| |
| if (argc != 3) |
| { |
| fputs("Usage: translate cups_language.po language\n", stderr); |
| return (1); |
| } |
| |
| if (access(argv[1], 0)) |
| cat = _cupsMessageLoad("cups.pot"); |
| else |
| cat = _cupsMessageLoad(argv[1]); |
| |
| if (!cat) |
| { |
| puts("Unable to load message catalog."); |
| return (1); |
| } |
| |
| if (!translate_messages(cat, argv[2])) |
| { |
| puts("Unable to translate message catalog."); |
| return (1); |
| } |
| |
| if (!save_messages(cat, argv[1])) |
| { |
| puts("Unable to save message catalog."); |
| return (1); |
| } |
| |
| return (0); |
| } |
| |
| |
| /* |
| * 'save_messages()' - Save messages to a .po file. |
| */ |
| |
| int /* O - 1 on success, 0 on error */ |
| save_messages(cups_array_t *cat, /* I - Message catalog */ |
| const char *filename) /* I - File to save to */ |
| { |
| _cups_message_t *m; /* Current message */ |
| cups_file_t *fp; /* File pointer */ |
| |
| |
| /* |
| * Open the message catalog... |
| */ |
| |
| if ((fp = cupsFileOpen(filename, "w")) == NULL) |
| return (0); |
| |
| /* |
| * Save the messages to a file... |
| */ |
| |
| for (m = (_cups_message_t *)cupsArrayFirst(cat); |
| m; |
| m = (_cups_message_t *)cupsArrayNext(cat)) |
| { |
| if (cupsFilePuts(fp, "msgid \"") < 0) |
| break; |
| |
| if (!write_string(fp, m->id)) |
| break; |
| |
| if (cupsFilePuts(fp, "\"\nmsgstr \"") < 0) |
| break; |
| |
| if (m->str) |
| { |
| if (!write_string(fp, m->str)) |
| break; |
| } |
| |
| if (cupsFilePuts(fp, "\"\n") < 0) |
| break; |
| } |
| |
| cupsFileClose(fp); |
| |
| return (!m); |
| } |
| |
| |
| /* |
| * 'translate_messages()' - Translate messages using Google. |
| */ |
| |
| int /* O - 1 on success, 0 on error */ |
| translate_messages(cups_array_t *cat, /* I - Message catalog */ |
| const char *lang) /* I - Output language... */ |
| { |
| /* |
| * Google provides a simple translation/language tool for translating |
| * from one language to another. It is far from perfect, however it |
| * can be used to get a basic translation done or update an existing |
| * translation when no other resources are available. |
| * |
| * Translation requests are sent as HTTP POSTs to |
| * "http://translate.google.com/translate_t" with the following form |
| * variables: |
| * |
| * Name Description Value |
| * -------- ---------------------------------- ---------------- |
| * hl Help language? "en" |
| * ie Input encoding "UTF8" |
| * langpair Language pair "en|" + language |
| * oe Output encoding "UTF8" |
| * text Text to translate translation string |
| */ |
| |
| int ret; /* Return value */ |
| _cups_message_t *m; /* Current message */ |
| int tries; /* Number of tries... */ |
| http_t *http; /* HTTP connection */ |
| http_status_t status; /* Status of POST request */ |
| char *idptr, /* Pointer into msgid */ |
| buffer[65536], /* Input/output buffer */ |
| *bufptr, /* Pointer into buffer */ |
| *bufend, /* Pointer to end of buffer */ |
| length[16]; /* Content length */ |
| int bytes; /* Number of bytes read */ |
| |
| |
| /* |
| * Connect to translate.google.com... |
| */ |
| |
| puts("Connecting to translate.google.com..."); |
| |
| if ((http = httpConnect("translate.google.com", 80)) == NULL) |
| { |
| perror("Unable to connect to translate.google.com"); |
| return (0); |
| } |
| |
| /* |
| * Scan the current messages, requesting a translation of any untranslated |
| * messages... |
| */ |
| |
| for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1; |
| m; |
| m = (_cups_message_t *)cupsArrayNext(cat)) |
| { |
| /* |
| * Skip messages that are already translated... |
| */ |
| |
| if (m->str && m->str[0]) |
| continue; |
| |
| /* |
| * Encode the form data into the buffer... |
| */ |
| |
| snprintf(buffer, sizeof(buffer), |
| "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang); |
| bufptr = buffer + strlen(buffer); |
| bufend = buffer + sizeof(buffer) - 5; |
| |
| for (idptr = m->id; *idptr && bufptr < bufend; idptr ++) |
| if (*idptr == ' ') |
| *bufptr++ = '+'; |
| else if (*idptr < ' ' || *idptr == '%') |
| { |
| sprintf(bufptr, "%%%02X", *idptr & 255); |
| bufptr += 3; |
| } |
| else if (*idptr != '&') |
| *bufptr++ = *idptr; |
| |
| *bufptr++ = '&'; |
| *bufptr = '\0'; |
| |
| sprintf(length, "%d", (int)(bufptr - buffer)); |
| |
| /* |
| * Send the request... |
| */ |
| |
| printf("\"%s\" = ", m->id); |
| fflush(stdout); |
| |
| tries = 0; |
| |
| do |
| { |
| httpClearFields(http); |
| httpSetField(http, HTTP_FIELD_CONTENT_TYPE, |
| "application/x-www-form-urlencoded"); |
| httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); |
| |
| if (httpPost(http, "/translate_t")) |
| { |
| httpReconnect(http); |
| httpPost(http, "/translate_t"); |
| } |
| |
| httpWrite2(http, buffer, bufptr - buffer); |
| |
| while ((status = httpUpdate(http)) == HTTP_CONTINUE); |
| |
| if (status != HTTP_OK && status != HTTP_ERROR) |
| httpFlush(http); |
| |
| tries ++; |
| } |
| while (status == HTTP_ERROR && tries < 10); |
| |
| if (status == HTTP_OK) |
| { |
| /* |
| * OK, read the translation back... |
| */ |
| |
| bufptr = buffer; |
| bufend = buffer + sizeof(buffer) - 1; |
| |
| while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0) |
| bufptr += bytes; |
| |
| if (bytes < 0) |
| { |
| /* |
| * Read error, abort! |
| */ |
| |
| puts("READ ERROR!"); |
| ret = 0; |
| break; |
| } |
| |
| *bufptr = '\0'; |
| |
| /* |
| * Find the first textarea element - that will have the translation data... |
| */ |
| |
| if ((bufptr = strstr(buffer, "<textarea")) == NULL) |
| { |
| /* |
| * No textarea, abort! |
| */ |
| |
| puts("NO TEXTAREA!"); |
| ret = 0; |
| break; |
| } |
| |
| if ((bufptr = strchr(bufptr, '>')) == NULL) |
| { |
| /* |
| * textarea doesn't end, abort! |
| */ |
| |
| puts("TEXTAREA SHORT DATA!"); |
| ret = 0; |
| break; |
| } |
| |
| bufptr ++; |
| |
| if ((bufend = strstr(bufptr, "</textarea>")) == NULL) |
| { |
| /* |
| * textarea doesn't close, abort! |
| */ |
| |
| puts("/TEXTAREA SHORT DATA!"); |
| ret = 0; |
| break; |
| } |
| |
| *bufend = '\0'; |
| |
| /* |
| * Copy the translation... |
| */ |
| |
| m->str = strdup(bufptr); |
| |
| /* |
| * Convert character entities to regular chars... |
| */ |
| |
| for (bufptr = strchr(m->str, '&'); |
| bufptr; |
| bufptr = strchr(bufptr + 1, '&')) |
| { |
| if (!strncmp(bufptr, "<", 4)) |
| { |
| *bufptr = '<'; |
| _cups_strcpy(bufptr + 1, bufptr + 4); |
| } |
| else if (!strncmp(bufptr, ">", 4)) |
| { |
| *bufptr = '>'; |
| _cups_strcpy(bufptr + 1, bufptr + 4); |
| } |
| else if (!strncmp(bufptr, "&", 5)) |
| _cups_strcpy(bufptr + 1, bufptr + 5); |
| } |
| |
| printf("\"%s\"\n", m->str); |
| } |
| else if (status == HTTP_ERROR) |
| { |
| printf("NETWORK ERROR (%s)!\n", strerror(httpError(http))); |
| ret = 0; |
| break; |
| } |
| else |
| { |
| printf("HTTP ERROR %d!\n", status); |
| ret = 0; |
| break; |
| } |
| } |
| |
| httpClose(http); |
| |
| return (ret); |
| } |
| |
| |
| /* |
| * 'write_string()' - Write a quoted string to a file. |
| */ |
| |
| int /* O - 1 on success, 0 on failure */ |
| write_string(cups_file_t *fp, /* I - File to write to */ |
| const char *s) /* I - String */ |
| { |
| while (*s) |
| { |
| switch (*s) |
| { |
| case '\n' : |
| if (cupsFilePuts(fp, "\\n") < 0) |
| return (0); |
| break; |
| |
| case '\r' : |
| if (cupsFilePuts(fp, "\\r") < 0) |
| return (0); |
| break; |
| |
| case '\t' : |
| if (cupsFilePuts(fp, "\\t") < 0) |
| return (0); |
| break; |
| |
| case '\\' : |
| if (cupsFilePuts(fp, "\\\\") < 0) |
| return (0); |
| break; |
| |
| case '\"' : |
| if (cupsFilePuts(fp, "\\\"") < 0) |
| return (0); |
| break; |
| |
| default : |
| if ((*s & 255) < ' ') |
| { |
| if (cupsFilePrintf(fp, "\\%o", *s) < 0) |
| return (0); |
| } |
| else if (cupsFilePutChar(fp, *s) < 0) |
| return (0); |
| break; |
| } |
| |
| s ++; |
| } |
| |
| return (1); |
| } |
| |
| |
| /* |
| * End of "$Id: translate.c 6921 2007-09-06 13:38:37Z mike $". |
| */ |