22
33import java .io .IOException ;
44import java .io .Reader ;
5+ import java .io .UnsupportedEncodingException ;
56import java .net .URL ;
67import java .net .URLConnection ;
78import java .net .URLEncoder ;
89import java .nio .charset .Charset ;
10+ import java .text .ParseException ;
11+ import java .text .SimpleDateFormat ;
12+ import java .util .ArrayList ;
13+ import java .util .Date ;
14+ import java .util .List ;
915import java .util .Locale ;
1016
1117/***************************************************************************************************************
1723 * @author Aaron Gokaslan (Skylion)
1824 ***************************************************************************************************************/
1925public final class GoogleTranslate { //Class marked as final since all methods are static
20-
26+
2127 /**
2228 * URL to query for Translation
2329 */
24- private final static String GOOGLE_TRANSLATE_URL = "http://translate.google.com/translate_a/t?client=t " ;
30+ private final static String GOOGLE_TRANSLATE_URL = "http://translate.google.com/translate_a/t" ;
2531
2632 /**
2733 * Private to prevent instantiation
2834 */
2935 private GoogleTranslate (){};
30-
36+
3137 /**
3238 * Converts the ISO-639 code into a friendly language code in the user's default language
3339 * For example, if the language is English and the default locale is French, it will return "anglais"
@@ -38,34 +44,69 @@ public final class GoogleTranslate { //Class marked as final since all methods a
3844 public static String getDisplayLanguage (String languageCode ){
3945 return (new Locale (languageCode )).getDisplayLanguage ();
4046 }
41-
47+
48+ /** Completes the complicated process of generating the URL
49+ * @param sourceLanguage The source language
50+ * @param targetLanguage The target language
51+ * @param text The text that you wish to generate
52+ * @return The generated URL as a string.
53+ */
54+ private static String generateURL (String sourceLanguage , String targetLanguage , String text ) throws UnsupportedEncodingException {
55+ String encoded = URLEncoder .encode (text , "UTF-8" ); //Encode
56+ StringBuilder sb = new StringBuilder ();
57+ sb .append (GOOGLE_TRANSLATE_URL );
58+ sb .append ("?client=t" ); //The client parameter
59+ sb .append ("&hl=en" ); //The language of the UI?
60+ sb .append ("&sl=" ); //Source language
61+ sb .append (sourceLanguage );
62+ sb .append ("&tl=" ); //Target language
63+ sb .append (targetLanguage );
64+ sb .append ("&text=" );
65+ sb .append (encoded );
66+ sb .append ("&multires=1" );//Necessary but unknown parameters
67+ sb .append ("&otf=0" );
68+ sb .append ("&pc=0" );
69+ sb .append ("&trs=1" );
70+ sb .append ("&ssel=0" );
71+ sb .append ("&tsel=0" );
72+ sb .append ("&sc=1" );
73+ sb .append ("&ie=UTF-8" ); //Input encoding
74+ sb .append ("&oe=UTF-8" ); //Output encoding
75+ sb .append ("&tk=" ); //Token authentication parameter
76+ sb .append (generateToken (encoded ));
77+ return sb .toString ();
78+ }
79+
4280 /**
4381 * Automatically determines the language of the original text
4482 * @param text represents the text you want to check the language of
4583 * @return The ISO-639 code for the language
4684 * @throws IOException if it cannot complete the request
4785 */
4886 public static String detectLanguage (String text ) throws IOException {
49- String encoded = URLEncoder . encode ( text , "UTF-8" ); //Encodes the string
50- URL url = new URL (GOOGLE_TRANSLATE_URL + "&text=" + encoded ); //Generates URL
87+ String urlText = generateURL ( "auto" , "en" , text );
88+ URL url = new URL (urlText ); //Generates URL
5189 String rawData = urlToText (url );//Gets text from Google
5290 return findLanguage (rawData );
5391 }
54-
55-
92+
93+
5694 /**
5795 * Automatically translates text to a system's default language according to its locale
5896 * Useful for creating international applications as you can translate UI strings
97+ * @see GoogleTranslate#translate(String, String, String)
5998 * @param text The text you want to translate
6099 * @return The translated text
61100 * @throws IOException if cannot complete request
62101 */
63102 public static String translate (String text ) throws IOException {
64103 return translate (Locale .getDefault ().getLanguage (), text );
65104 }
66-
105+
67106 /**
68- * Automatically detects language and translate to the targetLanguage
107+ * Automatically detects language and translate to the targetLanguage.
108+ * Allows Google to determine source language
109+ * @see GoogleTranslate#translate(String, String, String)
69110 * @param targetLanguage The language you want to translate into in ISO-639 format
70111 * @param text The text you actually want to translate
71112 * @return The translated text.
@@ -74,7 +115,7 @@ public static String translate(String text) throws IOException{
74115 public static String translate (String targetLanguage , String text ) throws IOException {
75116 return translate ("auto" ,targetLanguage , text );
76117 }
77-
118+
78119 /**
79120 * Translate text from sourceLanguage to targetLanguage
80121 * Specifying the sourceLanguage greatly improves accuracy over short Strings
@@ -85,9 +126,8 @@ public static String translate(String targetLanguage, String text) throws IOExce
85126 * @throws IOException if it cannot complete the request
86127 */
87128 public static String translate (String sourceLanguage , String targetLanguage , String text ) throws IOException {
88- String encoded = URLEncoder .encode (text , "UTF-8" ); //Encode
89- //Generates URL
90- URL url = new URL (GOOGLE_TRANSLATE_URL + "&sl=" + sourceLanguage + "&tl=" + targetLanguage + "&text=" + encoded );
129+ String urlText = generateURL (sourceLanguage , targetLanguage , text );
130+ URL url = new URL (urlText );//GOOGLE_TRANSLATE_URL + "&sl=" + sourceLanguage + "&tl=" + targetLanguage + "&text=" + encoded);
91131 String rawData = urlToText (url );//Gets text from Google
92132 if (rawData ==null ){
93133 return null ;
@@ -98,7 +138,7 @@ public static String translate(String sourceLanguage, String targetLanguage, Str
98138 }
99139 return raw [1 ];//Returns the translation
100140 }
101-
141+
102142 /**
103143 * Converts a URL to Text
104144 * @param url that you want to generate a String from
@@ -136,7 +176,7 @@ private static String findLanguage(String rawData){
136176 if (dashDetected ){
137177 int lastQuote = rawData .substring (i +2 ).indexOf ('"' );
138178 if (lastQuote >0 )
139- return rawData .substring (i +2 ,i +2 +lastQuote );
179+ return rawData .substring (i +2 ,i +2 +lastQuote );
140180 }
141181 else {
142182 String possible = rawData .substring (i +2 ,i +4 );
@@ -148,7 +188,7 @@ private static String findLanguage(String rawData){
148188 }
149189 return null ;
150190 }
151-
191+
152192 /**
153193 * Checks if all characters in text are letters.
154194 * @param text The text you want to determine the validity of.
@@ -162,6 +202,103 @@ private static boolean containsLettersOnly(String text){
162202 }
163203 return true ;
164204 }
165-
166-
205+
206+ /*************************** Cryptography section ************************************************
207+ ******************** Thank Dean1510 for the excellent code translation **************************/
208+
209+
210+ //TODO Possibly refactor code as utility class
211+
212+ /**
213+ * This function generates the b parameter for translation acting as the seed for the hashing algorithm.
214+ */
215+ private static int generateB () {
216+ SimpleDateFormat sdf = new SimpleDateFormat ("dd/MM/yyyy" , Locale .US );
217+
218+ Date start ;
219+ Date now ;
220+ try {
221+ start = sdf .parse ("01/01/1970" );
222+ now = new Date ();
223+ } catch (ParseException e ) {
224+ return 402890 ;
225+ }
226+ long diff = now .getTime () - start .getTime ();
227+ long hours = diff / (60 * 60 * 1000 ) % 24 ;
228+ long days = diff / (24 * 60 * 60 * 1000 );
229+ return (int ) (hours + days * 24 );
230+ }
231+
232+ /**
233+ * An implementation of an unsigned right shift.
234+ * Necessary since Java does not have unsigned ints.
235+ * @param x The number you wish to shift.
236+ * @param bits The number of bytes you wish to shift.
237+ * @return The shifted number, unsigned.
238+ */
239+ private static int shr32 (int x , int bits ) {
240+ if (x < 0 ) {
241+ long x_l = 0xffffffffl + x + 1 ;
242+ return (int ) (x_l >> bits );
243+ }
244+ return x >> bits ;
245+ }
246+
247+ private static int RL (int a , String b ) {//I am not entirely sure what this magic does.
248+ for (int c = 0 ; c < b .length () - 2 ; c += 3 ) {
249+ int d = b .charAt (c + 2 );
250+ d = d >= 65 ? d - 87 : d - 48 ;
251+ d = b .charAt (c + 1 ) == '+' ? shr32 (a , d ) : (a << d );
252+ a = b .charAt (c ) == '+' ? (a + d & 0xFFFFFFFF ) : a ^ d ;
253+ }
254+ return a ;
255+ }
256+
257+ /**
258+ * Generates the token needed for translation.
259+ * @param text The text you want to generate the token for.
260+ * @return The generated token as a string.
261+ */
262+ private static String generateToken (String text ) {
263+ int b = generateB ();
264+ int e = 0 ;
265+ int f = 0 ;
266+ List <Integer > d = new ArrayList <Integer >();
267+ for (; f < text .length (); f ++) {
268+ int g = text .charAt (f );
269+ if (0x80 > g ) {
270+ d .add (e ++, g );
271+ } else {
272+ if (0x800 > g ) {
273+ d .add (e ++, g >> 6 | 0xC0 );
274+ } else {
275+ if (0xD800 == (g & 0xFC00 ) && f + 1 < text .length () &&
276+ 0xDC00 == (text .charAt (f + 1 ) & 0xFC00 )) {
277+ g = 0x10000 + ((g & 0x3FF ) << 10 ) + (text .charAt (++f ) & 0x3FF );
278+ d .add (e ++, g >> 18 | 0xF0 );
279+ d .add (e ++, g >> 12 & 0x3F | 0x80 );
280+ } else {
281+ d .add (e ++, g >> 12 | 0xE0 );
282+ d .add (e ++, g >> 6 & 0x3F | 0x80 );
283+ }
284+ }
285+ d .add (e ++, g & 63 | 128 );
286+ }
287+ }
288+
289+ int a_i = b ;
290+ for (e = 0 ; e < d .size (); e ++) {
291+ a_i += d .get (e );
292+ a_i = RL (a_i , "+-a^+6" );
293+ }
294+ a_i = RL (a_i , "+-3^+b+-f" );
295+ long a_l ;
296+ if (0 > a_i ) {
297+ a_l = 0x80000000l + (a_i & 0x7FFFFFFF );
298+ } else {
299+ a_l = a_i ;
300+ }
301+ a_l %= Math .pow (10 , 6 );
302+ return String .format (Locale .US , "%d.%d" , a_l , a_l ^ b );
303+ }
167304}
0 commit comments