/** * Reads next line from the input and: * * <ul> * <li>Converts ascii-encoded \\uxxxx chars to normal characters. * <li>Converts \r, \n and \t to CR, line feed and tab. * <li>But! Keeps a backspace in '\ ', '\=', '\:' etc (non-trimmable space or * non-key-value-breaking :-) equals). * <ul> * Change from BufferedReader to LinebreakPreservingReader was part of fix for bug 1462566 */ protected String getNextLine(LinebreakPreservingReader reader) throws IOException, TranslationException { String ascii = reader.readLine(); if (ascii == null) { return null; } StringBuilder result = new StringBuilder(); for (int cp, len = ascii.length(), i = 0; i < len; i += Character.charCount(cp)) { cp = ascii.codePointAt(i); if (cp == '\\' && ascii.codePointCount(i, len) > 1) { i += Character.charCount(cp); cp = ascii.codePointAt(i); if (cp != 'u') { if (cp == 'n') { cp = '\n'; } else if (cp == 'r') { cp = '\r'; } else if (cp == 't') { cp = '\t'; } else { result.append('\\'); } } else if (dontUnescapeULiterals) { // Put back the \ we swallowed result.append('\\'); } else { // checking if the string is long enough if (ascii.codePointCount(i, len) < 1 + 4) { throw new TranslationException(OStrings.getString("RBFH_ERROR_ILLEGAL_U_SEQUENCE")); } int uStart = ascii.offsetByCodePoints(i, 1); int uEnd = ascii.offsetByCodePoints(uStart, 4); String uStr = ascii.substring(uStart, uEnd); try { cp = Integer.parseInt(uStr, 16); if (!Character.isValidCodePoint(cp)) { throw new TranslationException(OStrings.getString("RBFH_ERROR_ILLEGAL_U_SEQUENCE")); } i = uEnd - Character.charCount(cp); } catch (NumberFormatException ex) { throw new TranslationException(OStrings.getString("RBFH_ERROR_ILLEGAL_U_SEQUENCE"), ex); } } } result.appendCodePoint(cp); } return result.toString(); }
/** Doing the processing of the file... */ @Override public void processFile(BufferedReader reader, BufferedWriter outfile, FilterContext fc) throws IOException, TranslationException { LinebreakPreservingReader lbpr = new LinebreakPreservingReader(reader); // fix for bug 1462566 String str; // Support to show the comments (localization notes) into the Comments panel String comments; boolean noi18n = false; // Parameter in the options of filter to customize the target file removeStringsUntranslated = processOptions != null && "true".equalsIgnoreCase(processOptions.get(OPTION_REMOVE_STRINGS_UNTRANSLATED)); // Parameter in the options of filter to customize the behavior of the filter dontUnescapeULiterals = processOptions != null && "true".equalsIgnoreCase(processOptions.get(OPTION_DONT_UNESCAPE_U_LITERALS)); // Initialize the comments comments = null; while ((str = getNextLine(lbpr)) != null) { // Variable to check if a segment is translated boolean translatedSegment = true; String trimmed = str.trim(); // skipping empty strings if (trimmed.isEmpty()) { outfile.write(str + lbpr.getLinebreak()); // Delete the comments comments = null; continue; } // skipping comments int firstCp = trimmed.codePointAt(0); if (firstCp == '#' || firstCp == '!') { outfile.write(toAscii(str, false) + lbpr.getLinebreak()); // Save the comments comments = (comments == null ? str : comments + "\n" + str); // checking if the next string shouldn't be internationalized if (trimmed.indexOf("NOI18N") >= 0) { noi18n = true; } continue; } // reading the glued lines while (str.codePointBefore(str.length()) == '\\') { String next = getNextLine(lbpr); if (next == null) { next = ""; } // gluing this line (w/o '\' on this line) // with next line (w/o leading spaces) str = str.substring(0, str.offsetByCodePoints(str.length(), -1)) + leftTrim(next); } // key=value pairs int equalsPos = searchEquals(str); // writing out key String key; if (equalsPos >= 0) { key = str.substring(0, equalsPos).trim(); } else { key = str.trim(); } key = removeExtraSlashes(key); // writing segment is delayed until verifying that the translation was made // outfile.write(toAscii(key, true)); // advance if there're spaces or tabs after = if (equalsPos >= 0) { int equalsEnd = str.offsetByCodePoints(equalsPos, 1); while (equalsEnd < str.length()) { int cp = str.codePointAt(equalsEnd); if (cp != ' ' && cp != '\t') { break; } equalsEnd += Character.charCount(cp); } String equals = str.substring(equalsPos, equalsEnd); // writing segment is delayed until verifying that the translation was made // outfile.write(equals); // value, if any String value; if (equalsEnd < str.length()) { value = removeExtraSlashes(str.substring(equalsEnd)); } else { value = ""; } if (noi18n) { // if we don't need to internationalize outfile.write(toAscii(value, false)); noi18n = false; } else { value = value.replaceAll("\\n\\n", "\n \n"); // If there is a comment, show it into the Comments panel String trans = process(key, value, comments); // Delete the comments comments = null; // Check if the segment is not translated if ("--untranslated_yet--".equals(trans)) { translatedSegment = false; trans = value; } trans = trans.replaceAll("\\n\\s\\n", "\n\n"); trans = toAscii(trans, false); if (!trans.isEmpty() && trans.codePointAt(0) == ' ') { trans = '\\' + trans; } // Non-translated segments are written based on the filter options if (translatedSegment == true || removeStringsUntranslated == false) { outfile.write(toAscii(key, true)); outfile.write(equals); outfile.write(trans); outfile.write(lbpr.getLinebreak()); // fix for bug 1462566 } } } // This line of code is moved up to avoid blank lines // outfile.write(lbpr.getLinebreak()); // fix for bug 1462566 } }