001: package Language;
002:
003: import java.io.*;
004: import java.util.*;
005: import java.util.zip.*;
006:
007: import Schmortopf.Utility.Vectorizable;
008: import Schmortopf.Utility.io.FileUtilities;
009:
010: /** parse sentences to translate in the sourcecode
011: * the method ParseWholeSourceAndSaveInFile should be runned at each new release
012: * to allow translations. It produces a file named english_sentences.vec
013: * used by TranslationEditor
014: */
015: public class SourceSentencesParser {
016: /**
017: */
018: private SourceSentencesParser() {
019:
020: } // Constructor
021:
022: /** this parses the whole source code for sentences and writes them in a vector file
023: named Language/english_sentences.vec
024:
025: @return a termination status message
026: */
027: public static String ParseWholeSourceAndSaveInFile(File sourceDir,
028: StringBuffer warningBuffer) {
029: // works when running in the IDE
030: SourceSentencesParser ssp = new SourceSentencesParser();
031: Vector collected = ssp.collectStringsToTranslateRecurse(
032: sourceDir, sourceDir.getAbsolutePath(), warningBuffer);
033:
034: System.out.println("" + collected.size()
035: + " sentences found in source");
036:
037: if (collected.size() == 0) {
038: String msg = "Zero sentences to translate found in "
039: + sourceDir.getAbsolutePath()
040: + "\nStopping without saving.";
041: //warningBuffer.append("\n"+msg);
042: System.out.println(msg);
043: return msg;
044: }
045:
046: // save
047: Vector v = new Vector();
048: for (int i = 0; i < collected.size(); i++) {
049: try {
050: Sentence se = (Sentence) collected.elementAt(i);
051: v.add(se.getVectorRepresentation());
052: } catch (Exception e) {
053: e.printStackTrace();
054: }
055: }
056:
057: File out = new File("Language/english_sentences.vec");
058:
059: try {
060: Common.StoreVectorToFile(out, v);
061: Vector test = ReadEnglishSourceCodeSentencesFromFile();
062: } catch (Exception e) {
063: e.printStackTrace();
064: }
065:
066: return "" + collected.size() + " sentences parsed and stored.";
067: }
068:
069: /** if stored previously, read the sentences
070: */
071: public static Vector ReadEnglishSourceCodeSentencesFromFile() {
072: Vector sentences = new Vector();
073:
074: File in = new File("Language/english_sentences.vec");
075: if (!in.exists())
076: return sentences;
077:
078: try {
079: Vector v = Common.ReadVectorFromFile(in);
080: for (int i = 0; i < v.size(); i++) {
081: Vector sv = (Vector) v.elementAt(i);
082: Sentence se = new Sentence();
083: se.createFromVectorRepresentation(sv);
084: sentences.addElement(se);
085: }
086: } catch (Exception e) {
087: e.printStackTrace();
088: }
089:
090: return sentences;
091: }
092:
093: /** is used to read the "english_sentences.vec" from the jarfile
094: when the translation editor merge the language files with the
095: sentences file.
096: */
097: public static Vector ReadEnglishSentencesVectorFromJarFile()
098: throws Exception {
099: Vector sentences = new Vector();
100: ClassLoader cl = SentenceDictionary.class.getClassLoader();
101: if (cl == null) {
102: System.out
103: .println("Class loader is null in ReadEnglishSentencesVectorFromJarFile ");
104: // not found, maybe IDE mode ? not running from jar file
105: return sentences; //ReadFromFile(language);
106: }
107:
108: InputStream is = null;
109: try {
110: is = cl
111: .getResourceAsStream("Language/english_sentences.vec");
112: if (is == null) {
113: System.out
114: .println("ResourceAsStream is null for english_sentences.vec");
115: return sentences;
116: }
117: GZIPInputStream zipIn = new GZIPInputStream(is);
118: DataInputStream dis = new DataInputStream(zipIn);
119: Vector v = FileUtilities.ReceiveVector(dis, null, 0);
120: for (int i = 0; i < v.size(); i++) {
121: Vector sv = (Vector) v.elementAt(i);
122: Sentence se = new Sentence();
123: se.createFromVectorRepresentation(sv);
124: sentences.addElement(se);
125: }
126: return sentences;
127: } finally {
128: try {
129: is.close();
130: } catch (Exception e) {
131: }
132: is = null;
133: }
134: }
135:
136: /** collect all strings called with Languge.Translate() in the sourcecode
137: LIMITATION : actually not supported are:
138: multiline ""+"" and comments in the sentence
139: @return a vector of sentences
140: */
141: public Vector collectStringsToTranslateRecurse(File base,
142: String baseString, StringBuffer warningBuffer) {
143: Vector sentences = new Vector();
144:
145: //System.out.println("* "+base.getName());
146:
147: if (base.isFile()) {
148: if (base.getName().endsWith(".java")) {
149: sentences.addAll(collectStringsToTranslate(base,
150: baseString, warningBuffer));
151: }
152: }
153:
154: else if (base.isDirectory()) {
155: File[] files = base.listFiles();
156: for (int i = 0; i < files.length; i++) {
157: sentences.addAll(collectStringsToTranslateRecurse(
158: files[i], baseString, warningBuffer));
159: }
160: }
161: return sentences;
162: }
163:
164: /** @param sourceSentence is a sentence parsed in the sourcecode
165: replace the \\n \\t and \\u codes found in the source code,
166: but not double \ (\\\\)
167: ### must also replace unicode chars... \u0000
168: */
169: private String interpretSourceStrings(final String sourceSentence) {
170: String sent = sourceSentence;
171: final char BS = '\\';
172:
173: int pos = -1;
174:
175: while (true) {
176: pos = sent.indexOf(BS, pos + 1); // search for next single \, represented as \\ in string litteral (!)
177: if (pos == -1)
178: return sent; // no more command
179:
180: if (pos + 1 >= sent.length())
181: return sent; // end of string reached
182:
183: // next char
184: char cp1 = sent.charAt(pos + 1);
185: //System.out.println("pos="+pos+", cp1="+cp1);
186:
187: if (cp1 == '"')
188: sent = sent.substring(0, pos) + "\""
189: + sent.substring(pos + 2);
190: else if (cp1 == '\'')
191: sent = sent.substring(0, pos) + "'"
192: + sent.substring(pos + 2);
193: else if (cp1 == 'n')
194: sent = sent.substring(0, pos) + "\n"
195: + sent.substring(pos + 2);
196: else if (cp1 == 'r')
197: sent = sent.substring(0, pos) + "\r"
198: + sent.substring(pos + 2);
199: else if (cp1 == 't')
200: sent = sent.substring(0, pos) + "\t"
201: + sent.substring(pos + 2);
202: else if (cp1 == '\\')
203: sent = sent.substring(0, pos) + "\\"
204: + sent.substring(pos + 2);
205: else if (cp1 == 'u') {
206: // parse unicode
207:
208: //ensure we have four digits
209: if (pos + 6 >= sent.length())
210: return sent;
211: String unic = sent.substring(pos + 2, pos + 6);
212: try {
213: //System.out.println(unic);
214: int code = Integer.parseInt(unic);
215:
216: sent = sent.substring(0, pos) + ((char) code)
217: + sent.substring(pos + 6);
218: } catch (Exception e) {
219: // cannot parse unicode
220: System.out
221: .println("Cannot interpret unicode sequence in "
222: + sent);
223: return sent;
224: }
225: } else {
226: System.out
227: .println("Cannot interpret escape sequence in "
228: + sent);
229: }
230: }
231: }
232:
233: /** collect all strings called with Languge.Translate() in the sourcecode
234: @return a vector of Sentence objects
235: */
236: public Vector collectStringsToTranslate(File file, String basePath,
237: StringBuffer warningBuffer) {
238: Vector sentences = new Vector();
239: FileInputStream fis = null;
240: StringBuffer sb = new StringBuffer();
241: try {
242: fis = new FileInputStream(file);
243: byte[] buffer = new byte[256];
244: int read = 0;
245: while ((read = fis.read(buffer)) != -1) {
246: sb.append(new String(buffer, 0, read));
247: }
248: } catch (Exception e) {
249: } finally {
250: if (fis != null)
251: try {
252: fis.close();
253: } catch (Exception ee) {
254: }
255: }
256: String text = sb.toString();
257: int pos = text.indexOf(START);
258: while (pos != -1) {
259: // search opening "
260: int startPos = text.indexOf("\"", pos + 19);
261:
262: // search closing )
263: int endClosing = text.indexOf(")", startPos + 1);
264:
265: // search closing "
266: int endPos = text.indexOf("\"", startPos + 1);
267: int linePos = GetNumberOfReturnUpToPosition(text, pos);
268:
269: if (startPos == -1 // no opening "
270: || endClosing <= startPos // ) before " => no string, variable instead=> ok
271: //|| endClosing <= endPos // ) before " can occur if () is in the string
272: || endPos == -1 // no ending "
273: ) {
274:
275: String relativePath = ConvertSystemPathToJavaPath(file
276: .getAbsolutePath().substring(
277: basePath.length() + 1));
278:
279: // allow localisation from schmortopf output pane
280: //
281: String msg = "Language.Throwable: The sentence should be HARDCODED in Language.Translate_() "
282: + "\n\tat "
283: + relativePath
284: + " ("
285: + file.getName() + ":" + linePos + ")\r\n";
286:
287: System.out.println(msg);
288: warningBuffer.append("\n" + msg);
289:
290: // next, from pos+1
291: pos = text.indexOf(START, pos + 1);
292: } else if (text.charAt(pos - 1) != '"') {
293: String sp = interpretSourceStrings(text.substring(
294: startPos + 1, endPos));
295: String relativePath = file.getAbsolutePath().substring(
296: basePath.length() + 1);
297:
298: // avoid empty path
299: if (relativePath.length() == 0)
300: relativePath = file.getAbsolutePath();
301:
302: //System.out.println( relativePath );
303: sentences.addElement(new Sentence(sp, relativePath,
304: linePos));
305:
306: // test if number of arguments is OK.
307: try {
308: int na = Common.GetNumberOfParametersInSentence(sp);
309: } catch (Exception exc) {
310: String msg = "java.lang.Throwable: Bad parameter syntax "
311: + exc.getMessage()
312: + "\n\tat "
313: + Common
314: .ConvertPathToJavaClassPathSyntax(relativePath)
315: + " ("
316: + file.getName()
317: + ":"
318: + linePos
319: + ")\r\n";
320:
321: warningBuffer
322: .append("\nBad parameters in sentence="
323: + sp);
324: warningBuffer.append("\n" + msg);
325:
326: }
327:
328: // go to next
329: pos = text.indexOf(START, endPos + 1);
330: } else {
331: //ignore it, this is the START string itself, where "Language.Trans.." is defined
332:
333: // go to next
334: pos = text.indexOf(START, endPos + 1);
335: }
336:
337: }
338: return sentences;
339: }
340:
341: /** finds the string up to the closing )
342: for example in "\"Hello\" world " ); returns <"Hello" world>
343: */
344: private static String ParseSourceStringUpToClosingParenthesis(
345: String text) {
346: return text;
347: }
348:
349: /** used to retrieve line number from absolute char position, needed for the dummy exception
350: stacktrace
351: */
352: public static int GetNumberOfReturnUpToPosition(String content,
353: int position) {
354: int n = 1; // first line has number 1;
355:
356: int retPos = -1;
357: while ((retPos = content.indexOf("\n", retPos + 1)) != -1) {
358: if (retPos > position)
359: break;
360: n++;
361: }
362: return n;
363: }
364:
365: /** replace / with .
366: */
367: public static String ConvertSystemPathToJavaPath(String sysPath) {
368: String s = sysPath.replace('\\', '.');
369: s = s.replace('/', '.');
370: return s;
371: }
372:
373: public static final String START = "Language.Translate(";
374:
375: /* ----
376: Don't start this class directly,
377: use the SourceSentencesParserEditor instead
378: public static void main(String[] a)
379: {
380: StringBuffer warningBuffer = new StringBuffer();
381: System.out.println(
382: ParseWholeSourceAndSaveInFile(new File("c:/sources/schmortopf_ide/"), warningBuffer)
383: //ParseWholeSourceAndSaveInFile(new File("c:/proj/schmortopf_ide/"), warningBuffer)
384: );
385: if(warningBuffer.length()>0)
386: {
387: System.out.println("Warnings:"+warningBuffer.toString());
388: }
389: // Tests
390: //Language.Translate("ceci est un "+" test");
391: Language.Translate("ceci est un autre "
392: +" test");
393: //Leanguage.Translate("def %");
394: //Leanguage.Translate("ghi %");
395: //Leanguage.Translate("abc", "ppp");
396: new Throwable().printStackTrace();
397: }
398: ---- */
399:
400: } // SourceSentencesParser
|