diff --git a/README.txt b/README.txt
index 2fff1ce..bef8da5 100644
--- a/README.txt
+++ b/README.txt
@@ -1,9 +1,9 @@
You will need to have Java (JDK or JRE) 1.5 or above to execute this program.
-To start the program, just double-click on the MobiMetaEditorV0.15.jar file.
+To start the program, just double-click on the MobiMetaEditorV0.16.jar file.
If that doesn't work, type this from the command-line:
- java -jar MobiMetaEditorV0.15.jar
+ java -jar MobiMetaEditorV0.16.jar
This was written based on the MOBI file format describe in:
http://wiki.mobileread.com/wiki/MOBI
@@ -13,6 +13,9 @@ This application is licensed under the MIT License (http://www.opensource.org/li
ChangeLog
+v0.16
+- rewrote the language codes routines
+
v0.15
- added the ability to add/edit the TTS EXTH record
- fixed issues with ConcurrentModificationExceptions thrown
@@ -27,7 +30,7 @@ v0.13
- added a Header Info dialog, which details various fields in the PDB header, PalmDOC header, and MOBI header
- added in provisions to invoke debug and safe modes from the command line
- added in WhisperPrep, which lets users set ASINs and sets the CDEType to EBOK
- (to invoke, type "java -cp MobiMetaEditorV0.13.jar cli.WhisperPrep
+ (to invoke, type "java -cp MobiMetaEditorV0.16.jar cli.WhisperPrep
")
v0.12
diff --git a/src/gui/LanguageCodes.java b/src/gui/LanguageCodes.java
index 2883f81..4e96dad 100644
--- a/src/gui/LanguageCodes.java
+++ b/src/gui/LanguageCodes.java
@@ -1,74 +1,76 @@
package gui;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Vector;
+
public class LanguageCodes
{
- // these codes are taken from:
- // http://www.autoitscript.com/autoit3/docs/appendix/OSLangCodes.htm
- //
- public final static int[] code =
- { 0, 1078, 1052, 1025, 2049, 3073, 4097, 5121, 6145, 7169, 8193, 9217,
- 10241, 11265, 12289, 13313, 14337, 15361, 16385, 1067, 1068, 2092,
- 1069, 1059, 1026, 1027, 4, 1028, 2052, 3076, 4100, 5124, 1050, 1029,
- 1030, 19, 1043, 2067, 9, 1033, 2057, 3081, 4105, 5129, 6153, 7177,
- 8201, 9225, 10249, 11273, 12297, 13321, 1061, 1080, 1073, 1035, 12,
- 1036, 2060, 3084, 4108, 5132, 6156, 1079, 7, 1031, 2055, 3079, 4103,
- 5127, 1032, 1037, 1081, 1038, 1039, 1057, 16, 1040, 2064, 1041, 1087,
- 1111, 1042, 1062, 1063, 1071, 1086, 2110, 1102, 1044, 2068, 1045, 22,
- 1046, 2070, 1048, 1049, 1103, 2074, 3098, 1051, 1060, 10, 1034, 2058,
- 3082, 4106, 5130, 6154, 7178, 8202, 9226, 10250, 11274, 12298,
- 13322, 14346, 15370, 16394, 17418, 18442, 19466, 20490, 1089, 29, 1053,
- 2077, 1097, 1092, 1054, 1055, 1058, 1056, 1091, 2115, 1066 };
-
- public final static String[] description =
- { "Unspecified", "Afrikaans", "Albanian", "Arabic - Saudi Arabia",
- "Arabic - Iraq", "Arabic - Egypt", "Arabic - Libya",
- "Arabic - Algeria", "Arabic - Morocco", "Arabic - Tunisia",
- "Arabic - Oman", "Arabic - Yemen", "Arabic - Syria",
- "Arabic - Jordan", "Arabic - Lebanon", "Arabic - Kuwait",
- "Arabic - UAE", "Arabic - Bahrain", "Arabic - Qatar", "Armenian",
- "Azeri - Latin", "Azeri - Cyrillic", "Basque", "Belarusian",
- "Bulgarian", "Catalan", "Chinese", "Chinese - Taiwan", "Chinese - PRC",
- "Chinese - Hong Kong", "Chinese - Singapore", "Chinese - Macau",
- "Croatian", "Czech", "Danish", "Dutch", "Dutch - Standard",
- "Dutch - Belgian", "English", "English - United States",
- "English Ð United Kingdom", "English - Australian",
- "English - Canadian", "English - New Zealand", "English - Irish",
- "English - South Africa", "English - Jamaica",
- "English - Caribbean", "English - Belize", "English - Trinidad",
- "English - Zimbabwe", "English - Philippines", "Estonian",
- "Faeroese", "Farsi", "Finnish", "French", "French - Standard",
- "French - Belgian", "French - Canadian", "French - Swiss",
- "French - Luxembourg", "French - Monaco", "Georgian", "German",
- "German - Standard", "German - Swiss", "German - Austrian",
- "German - Luxembourg", "German - Liechtenstei", "Greek", "Hebrew",
- "Hindi", "Hungarian", "Icelandic", "Indonesian", "Italian",
- "Italian - Standard", "Italian - Swiss", "Japanese", "Kazakh",
- "Konkani", "Korean", "Latvian", "Lithuanian", "Macedonian",
- "Malay - Malaysia", "Malay - Brunei Darussalam", "Marathi",
- "Norwegian - Bokmal", "Norwegian - Nynorsk", "Polish", "Portugese",
- "Portuguese - Brazilian", "Portuguese - Standard", "Romanian",
- "Russian", "Sanskrit", "Serbian - Latin", "Serbian - Cyrillic",
- "Slovak", "Slovenian", "Spanish", "Spanish - Traditional Sort",
- "Spanish - Mexican", "Spanish - Modern Sort",
- "Spanish - Guatemala", "Spanish - Costa Rica", "Spanish - Panama",
- "Spanish - Dominican Republic", "Spanish - Venezuela",
- "Spanish - Colombia", "Spanish - Peru", "Spanish - Argentina",
- "Spanish - Ecuador", "Spanish - Chile", "Spanish - Uruguay",
- "Spanish - Paraguay", "Spanish - Bolivia", "Spanish - El Salvador",
- "Spanish - Honduras", "Spanish - Nicaragua",
- "Spanish - Puerto Rico", "Swahili", "Swedish", "Swedish - Finland",
- "Tamil", "Tatar", "Thai", "Turkish", "Ukrainian", "Urdu",
- "Uzbek - Latin", "Uzbek - Cyrillic", "Vietnamese" };
-
+ public final static String PROP_FILENAME = "languagecodes.properties";
+
+ private HashMap codeHash;
+ private HashMap descriptionHash;
+ private String[] descriptions;
- public static int codeToIndex(int key)
+ public LanguageCodes()
{
- int len = code.length;
- for (int i = 0; i < len; i++)
+ Properties props = new Properties();
+ try
+ {
+ props.load(ClassLoader.getSystemClassLoader().getResourceAsStream(PROP_FILENAME));
+ }
+ catch (IOException e)
{
- if (code[i] == key) return i;
+ // we really have to find a better way to handle this
}
- return -1;
+ codeHash = new HashMap();
+ descriptionHash = new HashMap();
+ Vector vec = new Vector();
+ Enumeration keys = props.keys();
+ while (keys.hasMoreElements())
+ {
+ String key = (String)keys.nextElement();
+ String description = props.getProperty(key) + " (" + key + ")";
+
+ try
+ {
+ Integer code = Integer.valueOf(key);
+ codeHash.put(code, description);
+ descriptionHash.put(description, code);
+ vec.add(description);
+ }
+ catch (NumberFormatException e)
+ {
+ }
+ Collections.sort(vec);
+ descriptions = vec.toArray(new String[vec.size()]);
+ }
+ }
+
+ public String[] getDescriptions()
+ {
+ return descriptions;
+ }
+
+ public boolean codeExists(int code)
+ {
+ return (codeToDescription(code) != null);
+ }
+
+ public int descriptionToCode(String description)
+ {
+ Integer code = descriptionHash.get(description);
+ if (code == null) return -1;
+
+ return code.intValue();
+ }
+
+ public String codeToDescription(int code)
+ {
+ return codeHash.get (Integer.valueOf(code));
}
}
diff --git a/src/gui/LanguageDialog.java b/src/gui/LanguageDialog.java
index d6c2f5b..085def7 100644
--- a/src/gui/LanguageDialog.java
+++ b/src/gui/LanguageDialog.java
@@ -47,6 +47,7 @@ public class LanguageDialog extends JDialog implements ActionListener
private boolean dictOutputExists;
private LanguageModel model;
+ private LanguageCodes langCodes;
/**
* Create the dialog.
@@ -58,48 +59,17 @@ public class LanguageDialog extends JDialog implements ActionListener
locale = model.getLocale();
dictInput = model.getDictInput();
dictOutput = model.getDictOutput();
- localeExists = (LanguageCodes.codeToIndex(locale) != -1);
- dictInputExists = (LanguageCodes.codeToIndex(dictInput) != -1);
- dictOutputExists = (LanguageCodes.codeToIndex(dictOutput) != -1);
-
- String[] localeChoices;
- String[] dictInputChoices;
- String[] dictOutputChoices;
+ langCodes = new LanguageCodes();
+ localeExists = langCodes.codeExists(locale);
+ dictInputExists = langCodes.codeExists(dictInput);
+ dictOutputExists = langCodes.codeExists(dictOutput);
// assemble choices for combo boxes
//
- if (localeExists)
- localeChoices = LanguageCodes.description;
- else
- {
- localeChoices = new String[LanguageCodes.description.length + 1];
- System.arraycopy(LanguageCodes.description, 0, localeChoices, 0,
- LanguageCodes.description.length);
- localeChoices[localeChoices.length - 1] = "Unknown (" + locale
- + ")";
- }
+ String[] localeChoices = buildChoices(locale);
+ String[] dictInputChoices = buildChoices(dictInput);
+ String[] dictOutputChoices = buildChoices(dictOutput);
- if (dictInputExists)
- dictInputChoices = LanguageCodes.description;
- else
- {
- dictInputChoices = new String[LanguageCodes.description.length + 1];
- System.arraycopy(LanguageCodes.description, 0, dictInputChoices, 0,
- LanguageCodes.description.length);
- dictInputChoices[dictInputChoices.length - 1] = "Unknown ("
- + dictInput + ")";
- }
-
- if (dictOutputExists)
- dictOutputChoices = LanguageCodes.description;
- else
- {
- dictOutputChoices = new String[LanguageCodes.description.length + 1];
- System.arraycopy(LanguageCodes.description, 0, dictOutputChoices,
- 0, LanguageCodes.description.length);
- dictOutputChoices[dictOutputChoices.length - 1] = "Unknown ("
- + dictOutput + ")";
- }
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setBounds(100, 100, 450, 300);
@@ -149,8 +119,11 @@ public class LanguageDialog extends JDialog implements ActionListener
}
{
cbLanguage = new JComboBox(localeChoices);
- cbLanguage.setSelectedIndex(localeExists ? LanguageCodes
- .codeToIndex(locale) : (localeChoices.length - 1));
+ if (localeExists)
+ cbLanguage.setSelectedItem(langCodes.codeToDescription(locale));
+ else
+ cbLanguage.setSelectedIndex(localeChoices.length - 1);
+
GridBagConstraints gbc_cbLanguage = new GridBagConstraints();
gbc_cbLanguage.insets = new Insets(0, 0, 5, 0);
gbc_cbLanguage.fill = GridBagConstraints.HORIZONTAL;
@@ -172,10 +145,11 @@ public class LanguageDialog extends JDialog implements ActionListener
}
{
cbDictInput = new JComboBox(dictInputChoices);
- cbDictInput
- .setSelectedIndex(dictInputExists ? LanguageCodes
- .codeToIndex(dictInput)
- : (dictInputChoices.length - 1));
+ if (dictInputExists)
+ cbDictInput.setSelectedItem(langCodes.codeToDescription(dictInput));
+ else
+ cbDictInput.setSelectedIndex(dictInputChoices.length - 1);
+
GridBagConstraints gbc_cbDictInput = new GridBagConstraints();
gbc_cbDictInput.insets = new Insets(0, 0, 5, 0);
gbc_cbDictInput.fill = GridBagConstraints.HORIZONTAL;
@@ -198,9 +172,11 @@ public class LanguageDialog extends JDialog implements ActionListener
}
{
cbDictOutput = new JComboBox(dictOutputChoices);
- cbDictOutput.setSelectedIndex(dictOutputExists ? LanguageCodes
- .codeToIndex(dictOutput)
- : (dictOutputChoices.length - 1));
+ if (dictOutputExists)
+ cbDictOutput.setSelectedItem(langCodes.codeToDescription(dictOutput));
+ else
+ cbDictOutput.setSelectedIndex(dictOutputChoices.length - 1);
+
GridBagConstraints gbc_cbDictOutput = new GridBagConstraints();
gbc_cbDictOutput.fill = GridBagConstraints.HORIZONTAL;
gbc_cbDictOutput.gridx = 1;
@@ -232,17 +208,16 @@ public class LanguageDialog extends JDialog implements ActionListener
if (source == okButton)
{
- int localeIndex = cbLanguage.getSelectedIndex();
- if ((localeIndex >= 0) && (localeIndex < LanguageCodes.code.length))
- locale = LanguageCodes.code[localeIndex];
+ int mappedCode;
+
+ mappedCode = langCodes.descriptionToCode((String)cbLanguage.getSelectedItem());
+ if (mappedCode != -1) locale = mappedCode;
- int dictInputIndex = cbDictInput.getSelectedIndex();
- if ((dictInputIndex >= 0) && (dictInputIndex < LanguageCodes.code.length))
- dictInput = LanguageCodes.code[dictInputIndex];
+ mappedCode = langCodes.descriptionToCode((String)cbDictInput.getSelectedItem());
+ if (mappedCode != -1) dictInput = mappedCode;
- int dictOutputIndex = cbDictOutput.getSelectedIndex();
- if ((dictOutputIndex >= 0) && (dictOutputIndex < LanguageCodes.code.length))
- dictOutput = LanguageCodes.code[dictOutputIndex];
+ mappedCode = langCodes.descriptionToCode((String)cbDictOutput.getSelectedItem());
+ if (mappedCode != -1) dictOutput = mappedCode;
model.setLanguages(locale, dictInput, dictOutput);
@@ -255,4 +230,20 @@ public class LanguageDialog extends JDialog implements ActionListener
dispose();
}
}
+
+ private String[] buildChoices(int code)
+ {
+ if (langCodes.codeExists(code))
+ return langCodes.getDescriptions();
+ else
+ {
+ String[] descriptions = langCodes.getDescriptions();
+ String[] choices = new String[descriptions.length + 1];
+ System.arraycopy(descriptions, 0, choices, 0,
+ descriptions.length);
+ choices[choices.length - 1] = "Unknown (" + code
+ + ")";
+ return choices;
+ }
+ }
}
diff --git a/src/languagecodes.properties b/src/languagecodes.properties
new file mode 100644
index 0000000..ce60419
--- /dev/null
+++ b/src/languagecodes.properties
@@ -0,0 +1,337 @@
+# Many thanks to ixtab on mobileread forums for the complete list!
+#
+
+1=ar
+2=bg
+3=ca
+4=zh
+5=cz
+6=da
+7=de
+8=el
+9=en
+10=es
+11=fi
+12=fr
+13=he
+14=hu
+15=is
+16=it
+17=ja
+18=ko
+19=nl
+20=nn
+21=pl
+22=pt
+24=ro
+25=ru
+26=hr
+27=sk
+28=sq
+29=sv
+30=th
+31=tr
+32=ur
+33=in
+34=uk
+35=be
+36=sl
+37=et
+38=lv
+39=lt
+40=tg
+41=fa
+42=vi
+43=hy
+44=az
+45=eu
+46=wen
+47=mk
+49=ts
+50=tn
+51=ve
+52=xh
+53=zu
+54=af
+55=ka
+56=fo
+57=hi
+58=mt
+59=se
+60=sco
+61=yi
+62=ms
+63=kk
+64=ky
+65=sw
+66=tk
+67=uz
+68=tt
+69=bn
+70=pa
+71=gu
+72=or
+73=ta
+74=te
+75=kn
+76=ml
+77=as
+78=mr
+79=sa
+80=mn
+81=bo
+82=cy
+83=km
+84=lo
+85=bu
+86=gl
+87=knn
+88=mni
+89=sd
+90=syr
+91=si
+92=chr
+93=iu
+94=am
+95=tjo
+96=ks
+97=ne
+98=fy
+99=ps
+100=fil
+101=dv
+102=bin
+103=ff
+104=ha
+105=ibb
+106=yo
+107=qu
+108=nso
+112=ig
+113=kr
+114=om
+115=ti
+116=gn
+117=haw
+118=la
+119=so
+120=ii
+128=ug
+129=mi
+1025=ar
+1026=bg
+1027=ca
+1028=zh-tw
+1029=cz
+1030=da
+1031=de
+1032=el
+1033=en
+1034=es-es
+1035=fi
+1036=fr
+1037=he
+1038=hu
+1039=is
+1040=it-it
+1041=ja
+1042=ko
+1043=nl-nl
+1044=nb
+1045=pl
+1046=pt
+1050=hr
+1051=sk
+1052=sq-al
+1053=sv
+1054=th
+1055=tr
+1056=ur
+1057=in
+1058=uk
+1059=be
+1060=sl
+1061=et
+1062=lv
+1063=lt
+1064=tg
+1065=fa
+1066=vi
+1067=hy-am
+1068=az-latn
+1069=eu
+1070=wen
+1071=mk
+1073=ts
+1074=tn
+1075=ve
+1076=xh
+1077=zu
+1078=af-za
+1079=ka
+1080=fo
+1081=hi
+1082=mt
+1083=se
+1084=sco
+1085=yi
+1086=ms-my
+1087=kk
+1088=ky-cyrl
+1089=sw
+1090=tk
+1091=uz-latn
+1092=tt
+1093=bn-in
+1094=pa
+1095=gu
+1096=or
+1097=ta
+1098=te
+1099=kn
+1100=ml
+1101=as
+1102=mr
+1103=sa
+1104=mn-cyrl
+1105=bo
+1106=cy
+1107=km
+1108=lo
+1109=bu
+1110=gl
+1111=knn
+1112=mni
+1113=sd-in
+1114=syr
+1115=si-lk
+1116=chr-us
+1117=iu
+1118=am-et
+1119=tjo-arab
+1120=ks-arab
+1121=ne
+1122=fy-nl
+1123=ps
+1124=fil
+1125=dv
+1126=bin
+1127=ff
+1128=ha
+1129=ibb
+1130=yo
+1131=qu-bo
+1132=nso
+1136=ig
+1137=kr
+1138=om
+1139=ti-et
+1140=gn
+1141=haw
+1142=la
+1143=so
+1144=ii
+1152=ug-cn
+1153=mi
+2049=ar-iq
+2052=zh
+2055=de-ch
+2057=en-gb
+2058=es-mx
+2060=fr-be
+2064=it-ch
+2067=nl-be
+2068=nn
+2070=pt-pt
+2072=ro
+2073=ru
+2074=sr-latn
+2077=sv-fi
+2080=ur-in
+2092=az-cyrl
+2108=ga-ie
+2110=ms-bn
+2115=uz-cyrl
+2117=bn-bd
+2118=pa-pk
+2128=mn-mong
+2129=bo-bt
+2137=sd-pk
+2143=tjo-latn
+2144=ks
+2145=ne-in
+2155=qu-ec
+2163=ti-er
+3073=ar-eg
+3076=zh-hk
+3079=de-at
+3081=en-au
+3084=fr-ca
+3098=sr-cyrl
+3179=qu-pe
+4097=ar-ly
+4100=zh-sg
+4103=de-lu
+4105=en-ca
+4106=es-gt
+4108=fr-ch
+4122=hr-bs
+5121=ar-dz
+5124=zh-mo
+5127=de-li
+5129=en-nz
+5130=es-cr
+5132=fr-lu
+5146=bs-bs
+6145=ar-ma
+6153=en-ie
+6154=es-pa
+6156=fr-mc
+7169=ar-tn
+7177=en-za
+7178=es-do
+7180=fr-419
+8193=ar-om
+8201=en-jm
+8202=es-ve
+8204=fr-re
+9217=ar-ye
+9225=en-419
+9226=es-co
+9228=fr-cd
+10241=ar-sy
+10249=en-bz
+10250=es-pe
+10252=fr-sn
+11265=ar-jo
+11273=en-tt
+11274=es-ar
+11276=fr-cm
+12289=ar-lb
+12297=en-zw
+12298=es-ec
+12300=fr-ci
+13313=ar-kw
+13321=en-ph
+13322=es-cl
+13324=fr-ml
+14337=ar-ae
+14345=en-id
+14346=es-uy
+14348=fr-ma
+15361=ar-bh
+15369=en-hk
+15370=es-py
+15372=fr-ht
+16385=ar-qa
+16393=en-in
+16394=es-bo
+17417=en-my
+17418=es-sv
+18441=en-sg
+18442=es-hn
+19466=es-ni
+20490=es-pr
+21514=es-us
+22538=es-419
+58380=fr-015