package com.limegroup.gnutella.i18n;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
/**
* Writes language info out in HTML format.
*/
class HTMLOutput {
/** @see LanguageInfo#getLink() */
static final String PRE_LINK =
"http://www.limewire.org/fisheye/viewrep/~raw,r=MAIN/limecvs/lib/messagebundles/";
private static final String DEFAULT_LINK =
PRE_LINK + LanguageLoader.BUNDLE_NAME + LanguageLoader.PROPS_EXT;
/** constant link to the translate mailing list. */
private static final String HTML_TRANSLATE_EMAIL_ADDRESS =
"<script type=\"text/javascript\" language=\"JavaScript\"><!--\n" +
"// Protected email script by Joe Maller JavaScripts available at http://www.joemaller.com\n" +
"// This script is free to use and distribute but please credit me and/or link to my site.\n" +
"e_mA_iL_E = ('limewire' + \".\" + 'org'); e_mA_iL_E = ('translate' + \"@\" + e_mA_iL_E);\n" +
"document.write('<a href=\"mai' + \"lto:\" + e_mA_iL_E + '\">' + e_mA_iL_E + '</a>');\n" +
"//--></script><noscript><a href=\"#\">[Email address protected by JavaScript:\n" +
"please enable JavaScript to contact me]</a></noscript>";
/** minimum completion levels for the status HTML page */
private static final double MIN_PERCENTAGE_COMPLETED = 0.75;
private static final double MIN_PERCENTAGE_NEED_REVISION = 0.65;
private static final double MIN_PERCENTAGE_MIDWAY = 0.45;
private static final int MIN_COUNT_STARTED = 20;
private final StringBuffer page;
private final DateFormat df;
private final NumberFormat pc;
private final Map/* <String code, LanguageInfo li> */langs;
private final int basicTotal;
/**
* Constructs a new HTML output.
*
* @param df
* @param pc
* @param langs
* @param basicTotal
*/
HTMLOutput(DateFormat df, NumberFormat pc, Map langs, int basicTotal) {
this.df = df;
this.pc = pc;
this.langs = langs;
this.basicTotal = basicTotal;
this.page = buildHTML();
}
/**
* Creates the HTML.
*
* @return the HTML page in a StringBuffer.
*/
StringBuffer buildHTML() {
List langsCompleted = new LinkedList();
List langsNeedRevision = new LinkedList();
List langsMidway = new LinkedList();
List langsStarted = new LinkedList();
List langsEmbryonic = new LinkedList();
Map charsets = new TreeMap(new CharsetNameComparator());
for (Iterator i = langs.entrySet().iterator(); i.hasNext();) {
final Map.Entry entry = (Map.Entry) i.next();
// final String code = (String)entry.getKey();
final LanguageInfo li = (LanguageInfo) entry.getValue();
final Properties props = li.getProperties();
final int count = props.size();
final double percentage = (double) count / (double) basicTotal;
li.setPercentage(percentage);
if (percentage >= MIN_PERCENTAGE_COMPLETED)
langsCompleted.add(li);
else if (percentage >= MIN_PERCENTAGE_NEED_REVISION)
langsNeedRevision.add(li);
else if (percentage >= MIN_PERCENTAGE_MIDWAY)
langsMidway.add(li);
else if (count >= MIN_COUNT_STARTED)
langsStarted.add(li);
else
langsEmbryonic.add(li);
String script = li.getScript();
List inScript = (List) charsets.get(script);
if (inScript == null) {
inScript = new LinkedList();
charsets.put(script, inScript);
}
inScript.add(li);
}
StringBuffer newpage = new StringBuffer();
buildStartOfPage(newpage);
buildStatus(newpage, langsCompleted, langsNeedRevision, langsMidway,
langsStarted, langsEmbryonic);
buildAfterStatus(newpage);
buildProgress(newpage, charsets);
buildEndOfPage(newpage);
return newpage;
}
/**
* Prints the HTML to 'out'.
*
* @param out
*/
void printHTML(PrintStream out) {
/*
* Make sure printed page contains only ASCII, converting all other code
* points to decimal NCRs. This will work whatever charset will be
* selected by the user's browser.
*/
int pageLength = page.length();
for (int index = 0; index < pageLength;) {
int c = page.charAt(index++); // char's are always positive
if (c < 160) { /* C0 or Basic Latin or C1 */
if (c >= 32 && c < 127 || c == '\t') /* Basic Latin or TAB */
out.print((char) c);
else if (c == '\n') /* LF */
out.println(); /* platform's newline sequence */
/* ignore all other C0 and C1 controls */
} else { /* Use NCRs */
/* special check for surrogate pairs */
if (c >= 0xD800 && c <= 0xDBFF && index < pageLength) {
char c2 = page.charAt(index);
if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
c = 0x10000 + ((c - 0xD800) << 10) + (c2 - 0xDC00);
index++;
}
}
out.print("");
out.print(c);// decimal NCR notation
out.print(';');
}
}
}
/**
* Builds the start of the page.
*/
private void buildStartOfPage(StringBuffer newpage) {
newpage.append(
" <div id=\"bod1\">\n" +
" <h1>Help Internationalize LimeWire!</h1>\n" +
" <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n" +
" <tr>\n" + /* Three columns */
" <td valign=\"top\" style=\"line-height: 16px;\">\n" +
/* Start column 1 (main content) */
" The LimeWire Open Source Project has embarked on an effort to\n" +
" internationalize LimeWire. If you are an avid English-speaking user\n" +
" fluent in another language, we need your help! Helping requires no\n" +
" programming knowledge and little computer savviness beyond using a word\n" +
" processor.<br />\n" +
" <br />\n" +
" <b>HOW LIMEWIRE SUPPORTS MULTIPLE LANGUAGES</b><br />\n" +
" <br />\n" +
" First, view this <a\n" +
" href=\"http://www.limewire.com/img/screenshots/search.jpg\"\n" +
" target=\"_blank\">LimeWire screen-shot</a>. Notice how the tabs\n" +
" (<b>Search</b>, <b>Monitor</b>, <b>Library</b>, etc.) and the buttons\n" +
" (<b>Download</b>, <b>Cancel</b>, etc.) have text on them. All\n" +
" elements of the LimeWire interface can be translated to any language very\n" +
" easily.<br />\n" +
" <br />\n" +
" This translation is accomplished by packaging all the words of the\n" +
" program into a "message bundle". A message bundle is more\n" +
" or less a list, with phrases corresponding to certain parts of the\n" +
" software. There are message bundles for different languages, so\n" +
" there is an English message bundle, a French message bundle, a Japanese\n" +
" message bundle, etc. In English, the text for the download button\n" +
" is "Download", whereas in French the text is "Charger"\n" +
" (which is French for "download").<br />\n" +
" <br />\n" +
" When you start LimeWire, the program loads the appropriate message bundle\n" +
" and uses its contents for any interface element that has text on it. \n" +
" For instance, this is the <a\n" +
"href=\"" + PRE_LINK + "MessagesBundle.properties\">English\n" +
" message bundle</a>. Note the line:<br />\n" +
" <blockquote>\n" +
" <table border=\"0\" cellspacing=\"1\" cellpadding=\"4\"" +
" bgcolor=\"#b1b1b1\">\n" +
" <tr bgcolor=\"#EFEFEF\">\n" +
" <td><code>\n" +
"SEARCH_DOWNLOAD_BUTTON_LABEL=Download</code></td>\n" +
" </tr>\n" +
" </table>\n" +
" </blockquote>\n" +
" This line indicates that the label used on the download button on\n" +
" the search tab should read "Download". Contrast this\n" +
" with the same line in the <a\n" +
"href=\"" + PRE_LINK + "MessagesBundle_fr.properties\">French\n" +
" message bundle</a>:<br />\n" +
" <blockquote>\n" +
" <table border=\"0\" cellspacing=\"1\" cellpadding=\"4\"\n" +
" bgcolor=\"#b1b1b1\">\n" +
" <tr bgcolor=\"#EFEFEF\">\n" +
" <td><code>\n" +
"#### SEARCH_DOWNLOAD_BUTTON_LABEL=Download<br />\n" +
"SEARCH_DOWNLOAD_BUTTON_LABEL=Charger</code></td>\n" +
" </tr>\n" +
" </table>\n" +
" </blockquote>\n" +
" Note that the line starting with a "#" is a comment line,\n" +
" meaning it is not used by LimeWire. The English translation will\n" +
" always be present as a reference. A label that is not yet\n" +
" translated in a bundle will look like the following:<br />\n" +
" <blockquote>\n" +
" <table border=\"0\" cellspacing=\"1\" cellpadding=\"4\"\n" +
" bgcolor=\"#b1b1b1\">\n" +
" <tr bgcolor=\"#EFEFEF\">\n" +
" <td><code>\n" +
"#### SOME_NEW_LABEL=New!<br />\n" +
"#? SOME_NEW_LABEL=</code></td>\n" +
" </tr>\n" +
" </table>\n" +
" </blockquote>\n" +
" To provide a translation, one just needs to append the translated text\n" +
" after the equal sign, and remove the leading comment mark and\n" +
" space. The French translation would look like the following:<br />\n" +
" <blockquote>\n" +
" <table border=\"0\" cellspacing=\"1\" cellpadding=\"4\"\n" +
" bgcolor=\"#b1b1b1\">\n" +
" <tr bgcolor=\"#EFEFEF\">\n" +
" <td><code>\n" +
"#### SOME_NEW_LABEL=New!<br />\n" +
"SOME_NEW_LABEL=Nouveau!</code></td>\n" +
" </tr>\n" +
" </table>\n" +
" </blockquote>\n" +
" <br />\n");
}
/**
* Builds the status portion of the page.
*/
private void buildStatus(StringBuffer newpage, List langsCompleted,
List langsNeedRevision, List langsMidway, List langsStarted,
List langsEmbryonic) {
newpage.append(
" <b>TRANSLATION STATUS</b>\n" +
" <br />\n" +
" <ol>\n");
// ### Need subject-verb agreement here; need to check if
// ### size of list == 1 or singular versus plural
buildStatus(newpage, langsCompleted,
" are complete and will require only small revisions during the project\n" +
" evolution.");
buildStatus(newpage, langsNeedRevision,
" are mostly complete and can still be used reliably, but may need some\n" +
" revisions and a few missing translations to work best with newest\n" +
" versions.");
buildStatus(newpage, langsMidway,
" have been completed for an old version, but may now require some work,\n" +
" tests and revisions plus additional missing translations to reach a\n" +
" reliable status.");
buildStatus(newpage, langsStarted,
" are partly translated but still unfinished, and their use in LimeWire\n" +
" may be difficult for native language users. Providing a more\n" +
" complete translation would be very much appreciated.");
buildStatus(newpage, langsEmbryonic,
" are only embryonic and need a complete translation. \n" +
" The current files are largely untranslated.");
newpage.append(
" </ol><br />\n");
}
/**
* Builds an individual bullet point in the status portion of the page.
*/
private void buildStatus(StringBuffer newpage, List langsList, String status) {
boolean first = true;
for (Iterator i = langsList.iterator(); i.hasNext();) {
LanguageInfo l = (LanguageInfo) i.next();
if (first)
newpage.append(
" <li>\n");
else if (!i.hasNext())
newpage.append(" and\n");
else
newpage.append(",\n");
newpage.append(
" " + l.getLink());
first = false;
}
if (!first)
newpage.append("\n" +
status + "</li>\n");
}
/**
* Builds the info after the status portion.
*/
private void buildAfterStatus(StringBuffer newpage) {
newpage.append(
" <b>GENERAL CONSIDERATIONS FOR TRANSLATORS</b><br />\n" +
" <br />\n" +
" Do not start with the existing message bundle installed with your current\n" +
" version of LimeWire. Make sure you <b>work on the latest version of\n" +
" a message bundle</b>. You can get the latest bundle by clicking on\n" +
" a language in the list on the right side of this page.<br />\n" +
" <br />\n" +
" When translating, adopt the common terminology used in your localized\n" +
" operating system. In some cases, some terms were imported from\n" +
" English, despite other terms already existing in your own language. \n" +
" If a local term can be used unambiguously, please use it in preference to\n" +
" the English term, even if you have seen many uses of this English term on\n" +
" web sites. A good translation must be understood by people who are\n" +
" not entirely savvy with Internet and computer jargon. Pay\n" +
" particularly attention to the non-technical translation of common terms:\n" +
" download, upload, host, byte, firewall, address, file, directory, #\n" +
" (number of), leaf (terminal node), etc.<br />\n" +
" <br />\n" +
" Avoid translating word for word and do not use blindly automatic\n" +
" translators. Be imaginative but make a clear and concise\n" +
" translation. For button labels and column names, do not translate\n" +
" them with long sentences, as they need to be short. Suppress some\n" +
" articles, or use abbreviations if necessary.<br />\n" +
" <br />\n" +
" During the translation process, you may <a\n" +
" href=\"http://www.limewire.org/mailinglist.shtml\">subscribe to the\n" +
" translate mailing list</a> where you may benefit from other translators'\n" +
" questions and knowledge as well as receive assistance in English or\n" +
" French.<br />\n" +
" <br />\n" +
" <b>HOW TO SUBMIT CORRECTIONS OR ENHANCEMENTS FOR YOUR LANGUAGE</b><br />\n" +
" <br />\n" +
" If your corrections are significant, you may send your complete message\n" +
" bundle to\n" +
HTML_TRANSLATE_EMAIL_ADDRESS + ". \n" +
" Please be sure to include all resource strings defined in the latest\n" +
" version of the existing message bundle before sending us your\n" +
" revision.<br />\n" +
" <br />\n" +
" For simple few corrections or additions, just send the corrected lines in\n" +
" the content body of an email (making sure to select the correct character\n" +
" encoding in your email tool before sending it so that non-ASCII\n" +
" characters are not lost or replaced), with your comments.<br />\n" +
" <br />\n" +
" <i>We will review submitted translations and integrate all valuable\n" +
" contributions as quickly as possible.</i><br />\n" +
" <br />\n" +
" <b>WHICH TOOL OR EDITOR TO USE FOR TRANSLATIONS</b><br />\n" +
" <br />\n" +
" For <b>Basic Latin or Western European Latin-based languages</b>, which\n" +
" can use the US-ASCII or ISO-8859-1 character set, any text editor (such\n" +
" as Notepad on Windows) can be used on Windows and Linux. Once a\n" +
" file is completed, it can be sent as a simple text file to\n" +
HTML_TRANSLATE_EMAIL_ADDRESS + ".<br />\n" +
" <br />\n" +
" For <b>Central European languages</b>, the preferred format is a simple\n" +
" text file encoded with the ISO-8859-2 character set, or a UTF-8 encoded\n" +
" simple text file (which can be edited with Notepad on Windows 2000/XP),\n" +
" or a correctly marked-up HTML document such as HTML email, or a Word\n" +
" document.<br />\n" +
" <br />\n" +
" For <b>other European languages</b>, the preferred format is a plain-text\n" +
" file, encoded preferably with UTF-8 or a ISO-8859-* character set that\n" +
" you should explicitly specify, or a correctly marked-up HTML document, or\n" +
" a Word document. Please specify your working operating system and\n" +
" editor you used to create plain-text files (we may support incoming\n" +
" Windows codepages or Mac charsets, but we will convert them to Unicode\n" +
" UTF-8 in our repository).<br />\n" +
" <br />\n" +
" For <b>Semitic languages</b> (Arabic, Hebrew...), the preferred format is\n" +
" a plain-text file edited with a editor that supports the right-to-left\n" +
" layout, encoded preferably with UTF-8 or a ISO-8859-* character set, in\n" +
" logical order. Be careful with the relative order of keys and\n" +
" values, and with the appearance of ASCII punctuations around\n" +
" right-to-left words: make sure that your editor uses the RTL layout with\n" +
" the edited text aligned on the right; please do not insert BiDi control\n" +
" overrides; but you may need to place LRE/PDF marks (U+202B/U+202C)\n" +
" locally around non-Semitic words inserted within Semitic sentences. \n" +
" Also the "<code>\\n</code>" sequences that encode a newline\n" +
" will be displayed within semitic text as "<code>n\\</code>": do\n" +
" not use BiDi override controls for such special sequence whose appearance\n" +
" in your editor is not important, but that MUST be entered with a leading\n" +
" backslash before the "n" character.<br />\n" +
" <br />\n" +
" For <b>Asian Languages</b>, the preferred submission format is a Unicode\n" +
" text file encoded with UTF-8. Users of Windows 2000/XP can use\n" +
" Notepad but you must explicitly select the UTF-8 encoding when saving\n" +
" your file. Users of localized versions of Windows 95/98/ME can only\n" +
" save their file in the native local "ANSI" encoding, and should\n" +
" then send us their translation by copying and pasting it in the content\n" +
" body of the email.<br />\n" +
" <br />\n" +
" <b>Mac users</b> should use a word processor and send us their\n" +
" translations in an unambiguous format. On Mac OSX, the best tool is\n" +
" "TextEdit", from the Jaguar accessories, with which you can\n" +
" directly edit and save plain-text files encoded with UTF-8.<br />\n" +
" <br />\n" +
" <b>Linux users</b> can also participate if they have a correct\n" +
" environment for their locale. Files can be edited with\n" +
" "vi", "emacs", or other editors.<br />\n" +
" <br />\n" +
" For further information about internationalization standards, language\n" +
" and country codes, character sets and encodings, the following web pages\n" +
" may be helpful:<br />\n" +
" <ul>\n" +
" <li>Language codes: <a\n" +
" href=\"http://www.loc.gov/standards/iso639-2/englangn.html\"\n" +
"target=\"_blank\">http://www.loc.gov/standards/iso639-2/englangn.html</a></li>\n" +
" <li>Country codes: <a\n" +
" href=\"http://www.iso.org/iso/en/prods-services/iso3166ma/index.html\"\n" +
"target=\"_blank\">http://www.iso.org/iso/en/prods-services/iso3166ma/index.html</a></li>\n" +
" <li>Character sets: <a\n" +
" href=\"http://www.w3.org/International/O-charset.html\"\n" +
"target=\"_blank\">http://www.w3.org/International/O-charset.html</a></li>\n" +
" <li>Letter database (languages and character sets): <a\n" +
" href=\"http://www.eki.ee/letter/\"\n" +
" target=\"_blank\">http://www.eki.ee/letter/</a></li>\n" +
" <li>Other internationalization data: <a\n" +
" href=\"http://www.unicode.org/unicode/onlinedat/resources.html\"\n" +
"target=\"_blank\">http://www.unicode.org/unicode/onlinedat/resources.html</a></li>\n" +
" </ul>\n" +
" An excellent tutorial on various character sets, including the ASCII\n" +
" variants, the ISO-8859 family, the Windows "ANSI code pages",\n" +
" Macintosh character codes, and Unicode (or its ISO/IEC 10646 repertoire)\n" +
" can be found at <a href=\"http://www.cs.tut.fi/~jkorpela/chars.html\"\n" +
" target=\"_blank\">http://www.cs.tut.fi/~jkorpela/chars.html</a>.<br />\n" +
" <br />\n" +
" Users that do not have the correct tools to edit a message bundle can\n" +
" send us an email in English or in French that explains their needs.<br />\n" +
" <br />\n" +
" <b>HOW TO TEST A NEW TRANSLATION</b><br />\n" +
" <br />\n" +
" Only Windows and Unix simple text editors can create a plain-text file\n" +
" which will work in LimeWire, and only for languages using the Western\n" +
" European Latin character set. Do not use "SimpleText" on\n" +
" Mac OS to edit properties files as SimpleText does not create plain-text\n" +
" files. Other translations need to be converted into regular\n" +
" properties files, encoded using the ISO-8859-1 Latin character set and\n" +
" Unicode escape sequences, with a tool "native2ascii" found in\n" +
" the Java Development Kit.<br />\n" +
" <br />\n" +
" You do not need to rename your translated and converted bundle, which can\n" +
" co-exist with the English version. LimeWire will load the\n" +
" appropriate resource file according to the\n" +
" "<code>LANGUAGE=</code>", and "<code>COUNTRY=</code>"\n" +
" settings stored in your "<code>limewire.props</code>"\n" +
" preferences file. The list on the right can help you to find the\n" +
" correct language code to use.<br />\n" +
" <br />\n" +
" Bundles are stored in a single compressed archive named\n" +
" "<code>MessagesBundles.jar</code>" installed with\n" +
" LimeWire. All bundles are named\n" +
" "MessagesBundle_xx.properties", where "xx" is\n" +
" replaced by the language code. Note that bundles for languages\n" +
" using non-Western European Latin characters will be converted from UTF-8\n" +
" to ASCII using a special format with hexadecimal Unicode escape\n" +
" sequences, prior to their inclusion in this archive. This can be\n" +
" performed using the <code>native2ascii</code> tool from the Java\n" +
" Development Kit. If you do not know how to proceed to test the\n" +
" translation yourself, ask us for assistance at\n" +
HTML_TRANSLATE_EMAIL_ADDRESS + ".<br />\n" +
" <br />\n" +
" <b>HOW TO CREATE A NEW TRANSLATION</b><br />\n" +
" <br />\n" +
" Users that wish to contribute with a new translation must be fluent in\n" +
" the target language, preferably native of a country where this language\n" +
" is official. Before starting your work, please contact us at\n" +
HTML_TRANSLATE_EMAIL_ADDRESS + ".<br />\n" +
" <br />\n" +
" </td>\n" + /* End of column 1 (spacing) */
" <td> </td>\n" + /* Column 2 (spacing) */
" <td valign=\"top\">\n" + /* Start of column 3 (status) */
/* Start shaded right rectangle */
" <table border=\"0\" cellspacing=\"1\" cellpadding=\"4\"\n" +
" bgcolor=\"#b1b1b1\" width=\"270\">\n" +
" <tr bgcolor=\"#EFEFEF\">\n" +
" <td valign=\"top\"><br />\n" +
" <b>LAST UPDATED: <font color=\"#FF0000\">" + df.format(new Date()) +
"</font><br />\n" +
" <br />\n" +
" To get the most recent version of a message bundle, <b>click on the\n" +
" corresponding language</b> in the following list.<br />\n" +
" <br />\n" +
" LATEST TRANSLATIONS STATUS:</b><br />\n");
}
/**
* Builds the progress table.
*/
private void buildProgress(StringBuffer newpage, Map charsets) {
newpage.append(
" <table width=\"250\" border=\"0\" cellpadding=\"0\" cellspacing=\"4\">");
List latin = (List) charsets.remove("Latin");
newpage.append(
" <tr>\n" +
" <td colspan=\"3\" valign=\"top\">" +
" <hr noshade size=\"1\">\n" +
" Languages written with Latin (Basic) characters:</td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td valign=\"top\"><a\n" +
" href=\"" + DEFAULT_LINK + "\"\n" +
" target=\"_blank\"><b>English</b> (US)</a></td>\n" +
" <td align=\"right\">(default)</td>\n" +
" <td>en</td>\n" +
" </tr>\n");
for (Iterator i = latin.iterator(); i.hasNext();) {
LanguageInfo l = (LanguageInfo) i.next();
newpage.append(
" <tr>\n" +
" <td><b>" + l.getLink() + "</b></td>\n" +
" <td align=\"right\">(" + pc.format(l.getPercentage()) + ")</td>\n" +
" <td>" + l.getCode() + "</td>\n" +
" </tr>\n");
}
for (Iterator i = charsets.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
String charset = (String) entry.getKey();
List l = (List) entry.getValue();
newpage.append(
" <tr>\n" +
" <td colspan=\"3\" valign=\"top\">\n" +
" <hr noshade size=\"1\">\n" +
" Languages written with " + charset + " characters:</td>\n" +
" </tr>\n");
for (Iterator j = l.iterator(); j.hasNext();) {
LanguageInfo li = (LanguageInfo) j.next();
newpage.append(
" <tr>\n" +
" <td><b>" + li.getLink() + "</b></td>\n" +
" <td align=\"right\">(" + pc.format(li.getPercentage()) + ")</td>\n" +
" <td>" + li.getCode() + "</td>\n" +
" </tr>\n");
}
}
newpage.append(
" </table>\n");
}
/**
* Builds the closing footers of the page.
*/
private void buildEndOfPage(StringBuffer newpage) {
newpage.append(
" </td>\n" +
" </tr>\n" +
" </table>\n" + /* End of shaded right rectangle */
" </td>\n" + /* End of column 3 (status) */
" </tr>\n" +
" </table>\n" + /* End of the 3 columns table below the title */
" </div>\n"); /* (div id="bod1") */
}
/**
* This Comparator sorts charset names in a prefered order. It is consistent
* with equals, so can be used to sort keys in a Map.
*/
private static class CharsetNameComparator implements Comparator {
/**
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Object arg0, Object arg1) {
if (arg0 == arg1 || arg0.equals(arg1))
return 0;
final String charsetName0 = (String) arg0;
final String charsetName1 = (String) arg1;
// Make Latin charsets sorted before others.
boolean has0 = charsetName0.contains("Latin");
boolean has1 = charsetName1.contains("Latin");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
if (has0 && has1) {
has0 = charsetName0.contains("Basic");
has1 = charsetName1.contains("Basic");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
has0 = charsetName0.contains("Western");
has1 = charsetName1.contains("Western");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
}
// Then sort alphabetic charsets.
has0 = charsetName0.contains("European");
has1 = charsetName1.contains("European");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
if (has0 & has1)
return charsetName0.compareTo(charsetName1);
has0 = charsetName0.contains("Cyrillic");
has1 = charsetName1.contains("Cyrillic");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
if (has0 & has1)
return charsetName0.compareTo(charsetName1);
// Then sort abjads charsets.
has0 = charsetName0.contains("Semitic");
has1 = charsetName1.contains("Semitic");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
if (has0 & has1)
return charsetName0.compareTo(charsetName1);
has0 = charsetName0.contains("Brahmic");
has1 = charsetName1.contains("Brahmic");
if (has0 && !has1)
return -1;
if (!has0 && has1)
return 1;
if (has0 & has1)
return charsetName0.compareTo(charsetName1);
// Sort the remaining complex charsets.
return charsetName0.compareTo(charsetName1);
}
}
}