Index: pom.xml
===================================================================
--- pom.xml (revision 1697788)
+++ pom.xml (working copy)
@@ -35,6 +35,19 @@
http://tika.apache.org/
+
+ com.optimaize.languagedetector
+ language-detector
+ 0.5
+
+
+
+ org.slf4j
+ slf4j-jdk14
+ 1.7.12
+ test
+
+
org.osgi
Index: src/main/java/org/apache/tika/language/LanguageConfidence.java
===================================================================
--- src/main/java/org/apache/tika/language/LanguageConfidence.java (revision 0)
+++ src/main/java/org/apache/tika/language/LanguageConfidence.java (revision 0)
@@ -0,0 +1,8 @@
+package org.apache.tika.language;
+
+public enum LanguageConfidence {
+
+ HIGH,
+ MEDIUM,
+ LOW
+}
Index: src/main/java/org/apache/tika/language/LanguageDetector.java
===================================================================
--- src/main/java/org/apache/tika/language/LanguageDetector.java (revision 0)
+++ src/main/java/org/apache/tika/language/LanguageDetector.java (revision 0)
@@ -0,0 +1,182 @@
+package org.apache.tika.language;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+// We should use the IANA registry for primary language names...see
+// http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
+// There must be a package that uses this dataset to support knowledge of
+// the default script, etc. And how to map from - (e.g. 'zh-CN')
+// to ('cmn'), or - to ('zh-cmn' => 'cmn')
+// We'd also want to know the default sublang for a macro language ('zh' => 'zh-cmn')
+// There's also mapping 'zh-CN' to 'cmn-Hans' (simplified chinese script)
+
+// TODO decide how deep to go into supporting extended language tags, see
+// http://www.w3.org/International/articles/language-tags/. For example,
+// what should you expect from calling hasModel("en-GB") if there's only
+// a model for "en"?
+
+// This is mostly an issue for interpreting language tags in (X)HTML docs,
+// and maybe XML if we really care. In those cases you could get something
+// like "ast" (three letter language code), or even zh-cmn-Hant-SG
+// (Chinese, Mandarin, Traditional script, in Singapore) plus additional:
+// language-extlang-script-region-variant-extension-privateuse
+
+// The full spec is at http://www.rfc-editor.org/rfc/bcp/bcp47.txt
+
+public abstract class LanguageDetector {
+
+ // True if text is expected to be a mix of languages, and thus higher-resolution
+ // detection must be done to avoid under-sampling the text.
+ protected boolean mixedLanguages = false;
+
+ // True if the text is expected to be 'short' (typically less than 100 chars), and
+ // thus a different algorithm and/or set of profiles should be used.
+ protected boolean shortText = false;
+
+ public boolean isMixedLanguages() {
+ return mixedLanguages;
+ }
+
+ public LanguageDetector setMixedLanguages(boolean mixedLanguages) {
+ this.mixedLanguages = mixedLanguages;
+ return this;
+ }
+
+ public boolean isShortText() {
+ return shortText;
+ }
+
+ public LanguageDetector setShortText(boolean shortText) {
+ this.shortText = shortText;
+ return this;
+ }
+
+ /**
+ * Load (or re-load) all available language models. This must
+ * be called after any settings that would impact the models
+ * being loaded (e.g. mixed language/short text), but
+ * before any of the document processing routines (below)
+ * are called. Note that it only needs to be called once.
+ *
+ * @return this
+ */
+ public abstract LanguageDetector loadModels() throws IOException;
+
+ /**
+ * Load (or re-load) the models specified in . These use the
+ * ISO 639-1 names, with an optional "-" for more
+ * specific specification (e.g. "zh-CN" for Chinese in China).
+ *
+ * @param languages list of target languages.
+ * @return this
+ */
+ public abstract LanguageDetector loadModels(Set languages) throws IOException;
+
+ /**
+ * Provide information about whether a model exists for a specific
+ * language.
+ *
+ * @param language ISO 639-1 name for language
+ * @return true if a model for this language exists.
+ */
+ public abstract boolean hasModel(String language);
+
+ /**
+ * Set the a-priori probabilities for these languages. The provided map uses the language
+ * as the key, and the probability (0.0 > probability < 1.0) of text being in that language.
+ * Note that if the probabilities don't sum to 1.0, these values will be normalized.
+ *
+ * If hasModel() returns false for any of the languages, an IllegalArgumentException is thrown.
+ *
+ * Use of these probabilities is detector-specific, and thus might not impact the results at all.
+ * As such, these should be viewed as a hint.
+ *
+ * @param languageProbabilities Map from language to probability
+ * @return this
+ */
+ public abstract LanguageDetector setPriors(Map languageProbabilities) throws IOException;
+
+ // ============================================================
+ // The routines below are called when processing a document
+ // ============================================================
+
+ /**
+ * Reset statistics about the current document being processed
+ */
+ public abstract void reset();
+
+ /**
+ * Add statistics about this text for the current document. Note
+ * that we assume an implicit word break exists before/after
+ * each of these runs of text.
+ *
+ * @param cbuf Character buffer
+ * @param off Offset into cbuf to first character in the run of text
+ * @param len Number of characters in the run of text.
+ */
+ public abstract void addText(char[] cbuf, int off, int len);
+
+ /**
+ * Add to the statistics being accumulated for the current
+ * document. Note that this is a default implementation for adding
+ * a string (not optimized)
+ *
+ * @param text Characters to add to current statistics.
+ */
+ public void addText(CharSequence text) {
+ char[] chars = text.toString().toCharArray();
+ addText(chars, 0, chars.length);
+ }
+
+
+ /**
+ * Tell the caller whether more text is required for the current document
+ * before the language can be reliably detected.
+ *
+ * Implementations can override this to do early termination of stats
+ * collection, which can improve performance with longer documents.
+ *
+ * Note that detect() can be called even when this returns false
+ *
+ * @return true if we have enough text for reliable detection.
+ */
+ public boolean hasEnoughText() {
+ return false;
+ }
+
+ /**
+ * Detect languages based on previously submitted text (via addText calls).
+ *
+ * @return list of all possible languages with at least medium confidence,
+ * sorted by confidence from highest to lowest.
+ */
+ public abstract List detectAll();
+
+ public LanguageResult detect() {
+ List results = detectAll();
+ return results.isEmpty() ? null : results.get(0);
+ }
+
+ /**
+ * Utility wrapper that detects the language of a given chunk of text.
+ *
+ * @param text String to add to current statistics.
+ * @return list of all possible languages with at least medium confidence,
+ * sorted by confidence from highest to lowest.
+ */
+ public List detectAll(String text) {
+ reset();
+ addText(text);
+ return detectAll();
+ }
+
+ public LanguageResult detect(CharSequence text) {
+ reset();
+ addText(text);
+ return detect();
+ }
+
+}
Index: src/main/java/org/apache/tika/language/LanguageHandler.java
===================================================================
--- src/main/java/org/apache/tika/language/LanguageHandler.java (revision 0)
+++ src/main/java/org/apache/tika/language/LanguageHandler.java (revision 0)
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.language;
+
+import org.apache.tika.sax.WriteOutContentHandler;
+
+/**
+ * SAX content handler that updates a language detector based on all the
+ * received character content.
+ *
+ * @since Apache Tika 0.10
+ */
+public class LanguageHandler extends WriteOutContentHandler {
+
+ private final LanguageWriter writer;
+
+ public LanguageHandler(LanguageWriter writer) {
+ super(writer);
+
+ this.writer = writer;
+ }
+
+ public LanguageHandler(LanguageDetector detector) {
+ this(new LanguageWriter(detector));
+ }
+
+ /**
+ * Returns the language detector used by this content handler.
+ * Note that the returned detector gets updated whenever new SAX events
+ * are received by this content handler.
+ *
+ * @return language detector
+ */
+ public LanguageDetector getDetector() {
+ return writer.getDetector();
+ }
+
+}
Index: src/main/java/org/apache/tika/language/LanguageNames.java
===================================================================
--- src/main/java/org/apache/tika/language/LanguageNames.java (revision 0)
+++ src/main/java/org/apache/tika/language/LanguageNames.java (revision 0)
@@ -0,0 +1,35 @@
+package org.apache.tika.language;
+
+import java.util.Locale;
+
+public class LanguageNames {
+
+ public static String makeName(String language, String script, String region) {
+ Locale locale = new Locale.Builder().setLanguage(language).setScript(script).setRegion(region).build();
+ return locale.toLanguageTag();
+ }
+
+ public static String normalizeName(String languageTag) {
+ Locale locale = Locale.forLanguageTag(languageTag);
+ return locale.toLanguageTag();
+ }
+
+ public static boolean equals(String languageTagA, String languageTagB) {
+ Locale localeA = Locale.forLanguageTag(languageTagA);
+ Locale localeB = Locale.forLanguageTag(languageTagB);
+
+ // TODO Fill in script if missing and something we could derive from lang+region
+ // e.g. zh-CN => zh-Hans-CN, zh-TW => zh-Hant-TW.
+
+ // TODO Treat missing script == present script, if present script is default (suppressed) for
+ // the language. So "en-Latn" == "en"
+
+ // TODO probably OK to ignore extensions
+
+ // TODO Do we want/need a fuzzy match for region (and script)
+ // E.g. are 'en' and 'en-GB' equal? Depends on the direction, e.g. if you want 'en', and
+ // you get back something more specific (en-GB) then that's OK, but if you explicitly want
+ // en-GB and you get back en then that might not be OK.
+ return localeA.equals(localeB);
+ }
+}
Index: src/main/java/org/apache/tika/language/LanguageResult.java
===================================================================
--- src/main/java/org/apache/tika/language/LanguageResult.java (revision 0)
+++ src/main/java/org/apache/tika/language/LanguageResult.java (revision 0)
@@ -0,0 +1,73 @@
+package org.apache.tika.language;
+
+public class LanguageResult {
+
+ private String language;
+
+ private LanguageConfidence confidence;
+
+ // rawScore should be a number from 0.0 to 1.0, with higher values implying
+ // greater confidence.
+ private float rawScore;
+
+ /**
+ *
+ * @param language ISO 639-1 language code (plus optional "-")
+ * @param rawScore confidence of detector in the result.
+ */
+ public LanguageResult(String language, LanguageConfidence confidence, float rawScore) {
+ this.language = language;
+ this.confidence = confidence;
+ this.rawScore = rawScore;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public float getRawScore() {
+ return rawScore;
+ }
+
+ public float getConfidence() {
+ return rawScore;
+ }
+
+ public boolean isReasonablyCertain() {
+ return confidence == LanguageConfidence.HIGH;
+ }
+
+ /**
+ * Return true if the target language matches the detected language. We consider
+ * it a match if, for the precision requested or detected, it matches. This means:
+ *
+ * target | detected | match?
+ * zh | en | false
+ * zh | zh | true
+ * zh | zh-CN | true
+ * zh-CN | zh | true
+ * zh-CN | zh-TW | false
+ * zh-CN | zh-cn | true (case-insensitive)
+ *
+ * @param language
+ * @return
+ */
+ public boolean isLanguage(String language) {
+ String[] targetLanguage = language.split("\\-");
+ String[] resultLanguage = this.language.split("\\-");
+
+ int minLength = Math.min(targetLanguage.length, resultLanguage.length);
+ for (int i = 0; i < minLength; i++) {
+ if (!targetLanguage[i].equalsIgnoreCase(resultLanguage[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: %s (%f)", language, confidence, rawScore);
+ }
+}
Index: src/main/java/org/apache/tika/language/LanguageWriter.java
===================================================================
--- src/main/java/org/apache/tika/language/LanguageWriter.java (revision 0)
+++ src/main/java/org/apache/tika/language/LanguageWriter.java (revision 0)
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.language;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Writer that builds a language profile based on all the written content.
+ *
+ * @since Apache Tika 0.10
+ */
+public class LanguageWriter extends Writer {
+
+ private final LanguageDetector detector;
+
+ public LanguageWriter(LanguageDetector detector) {
+ this.detector = detector;
+ detector.reset();
+ }
+
+ /**
+ * Returns the language detector used by this writer. Note that
+ * the returned language detector gets updated whenever new characters
+ * are written.
+ *
+ * @return language detector
+ */
+ public LanguageDetector getDetector() {
+ return detector;
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) {
+ detector.addText(cbuf, off, len);
+ }
+
+ /**
+ * Ignored.
+ */
+ @Override
+ public void close() throws IOException {
+ }
+
+ /**
+ * Ignored.
+ */
+ @Override
+ public void flush() {
+ }
+
+ public void reset() {
+ detector.reset();
+ }
+}
Index: src/main/java/org/apache/tika/language/OptimaizeLangDetector.java
===================================================================
--- src/main/java/org/apache/tika/language/OptimaizeLangDetector.java (revision 0)
+++ src/main/java/org/apache/tika/language/OptimaizeLangDetector.java (revision 0)
@@ -0,0 +1,171 @@
+package org.apache.tika.language;
+
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.optimaize.langdetect.DetectedLanguage;
+import com.optimaize.langdetect.LanguageDetectorBuilder;
+import com.optimaize.langdetect.i18n.LdLocale;
+import com.optimaize.langdetect.ngram.NgramExtractors;
+import com.optimaize.langdetect.profiles.BuiltInLanguages;
+import com.optimaize.langdetect.profiles.LanguageProfile;
+import com.optimaize.langdetect.profiles.LanguageProfileReader;
+
+/**
+ * Implementation of the LanguageDetector API that uses
+ * https://github.com/optimaize/language-detector
+ */
+public class OptimaizeLangDetector extends LanguageDetector {
+
+ private static final int MAX_CHARS_FOR_DETECTION = 20000;
+ private static final int MAX_CHARS_FOR_SHORT_DETECTION = 200;
+
+ private com.optimaize.langdetect.LanguageDetector detector;
+ private CharArrayWriter writer;
+ private Set languages;
+ private Map languageProbabilities;
+
+ public OptimaizeLangDetector() {
+ super();
+
+ writer = new CharArrayWriter(MAX_CHARS_FOR_DETECTION);
+ }
+
+ @Override
+ public LanguageDetector loadModels() throws IOException {
+ List languageProfiles = new LanguageProfileReader().readAllBuiltIn();
+
+ // FUTURE when the "language-detector" project supports short profiles, check if
+ // isShortText() returns true and switch to those.
+
+ languages = new HashSet<>();
+ for (LanguageProfile profile : languageProfiles) {
+ languages.add(makeLanguageName(profile.getLocale()));
+ }
+
+ detector = createDetector(languageProfiles);
+
+ return this;
+
+ }
+
+ private String makeLanguageName(LdLocale locale) {
+ return LanguageNames.makeName(locale.getLanguage(), locale.getScript().orNull(), locale.getRegion().orNull());
+ }
+
+ @Override
+ public LanguageDetector loadModels(Set languages) throws IOException {
+
+ // Normalize languages.
+ this.languages = new HashSet<>(languages.size());
+ for (String language : languages) {
+ this.languages.add(LanguageNames.normalizeName(language));
+ }
+
+ // TODO what happens if you request a language that has no profile?
+ Set locales = new HashSet<>();
+ for (LdLocale locale : BuiltInLanguages.getLanguages()) {
+ String languageName = makeLanguageName(locale);
+ if (this.languages.contains(languageName)) {
+ locales.add(locale);
+ }
+ }
+
+ detector = createDetector(new LanguageProfileReader().readBuiltIn(locales));
+
+ return this;
+ }
+
+ private com.optimaize.langdetect.LanguageDetector createDetector(List languageProfiles) {
+ // FUTURE decide whether we really want to use the short text algorithm when dealing with mixed languages,
+ // as that would get really, really slow for big chunks of text.
+ LanguageDetectorBuilder builder = LanguageDetectorBuilder.create(NgramExtractors.standard())
+ .shortTextAlgorithm(mixedLanguages ? Integer.MAX_VALUE : 100)
+ .withProfiles(languageProfiles);
+
+ if (languageProbabilities != null) {
+ Map languageWeights = new HashMap<>(languageProbabilities.size());
+ for (String language : languageProbabilities.keySet()) {
+ Double priority = (double)languageProbabilities.get(language);
+ languageWeights.put(LdLocale.fromString(language), priority);
+ }
+
+ builder.languagePriorities(languageWeights);
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ public boolean hasModel(String language) {
+ return languages.contains(language);
+ }
+
+ @Override
+ public LanguageDetector setPriors(Map languageProbabilities) throws IOException {
+ this.languageProbabilities = languageProbabilities;
+
+ loadModels(languageProbabilities.keySet());
+
+ return this;
+ }
+
+ @Override
+ public void reset() {
+ writer.reset();
+ }
+
+ @Override
+ public void addText(char[] cbuf, int off, int len) {
+ if (hasEnoughText()) {
+ return; // do nothing if we've already got enough text.
+ }
+
+ writer.write(cbuf, off, len);
+
+ // FUTURE - use support to get padding char from NGramExtractors.standard().
+ // We'd like to get the textPadding character from the NGramExtractor, but
+ // that's not exposed. NGramExtractors.standard() returns extractor with ' '
+ // as padding, so that's what we'll use here.
+ writer.write(' ');
+ }
+
+ @Override
+ public List detectAll() {
+ // TODO throw exception if models haven't been loaded, or auto-load all?
+
+ List result = new ArrayList<>();
+
+ List rawResults = detector.getProbabilities(writer.toString());
+ for (DetectedLanguage rawResult : rawResults) {
+ // TODO figure out right level for confidence brackets.
+ LanguageConfidence confidence = rawResult.getProbability() > 0.9 ? LanguageConfidence.HIGH : LanguageConfidence.MEDIUM;
+ result.add(new LanguageResult(makeLanguageName(rawResult.getLocale()), confidence, (float)rawResult.getProbability()));
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean hasEnoughText() {
+ return writer.size() >= getTextLimit();
+ }
+
+ private int getTextLimit() {
+ int limit = (shortText ? MAX_CHARS_FOR_SHORT_DETECTION : MAX_CHARS_FOR_DETECTION);
+
+ // We want more text if we're processing documents that have a mixture of languages.
+ // FUTURE - figure out right amount to bump up the limit.
+ if (mixedLanguages) {
+ limit *= 2;
+ }
+
+ return limit;
+ }
+}
Index: src/main/java/org/apache/tika/language/ProfilingHandler.java
===================================================================
--- src/main/java/org/apache/tika/language/ProfilingHandler.java (revision 1697788)
+++ src/main/java/org/apache/tika/language/ProfilingHandler.java (working copy)
@@ -21,6 +21,8 @@
/**
* SAX content handler that builds a language profile based on all the
* received character content.
+ *
+ * TODO deprecate this.
*
* @since Apache Tika 0.5
*/
Index: src/main/java/org/apache/tika/language/ProfilingWriter.java
===================================================================
--- src/main/java/org/apache/tika/language/ProfilingWriter.java (revision 1697788)
+++ src/main/java/org/apache/tika/language/ProfilingWriter.java (working copy)
@@ -23,6 +23,8 @@
* Writer that builds a language profile based on all the written content.
*
* @since Apache Tika 0.5
+ *
+ * TODO deprecate this, and have it just delegate to LanguageWriter
*/
public class ProfilingWriter extends Writer {
Index: src/test/java/org/apache/tika/language/LanguageDetectorTest.java
===================================================================
--- src/test/java/org/apache/tika/language/LanguageDetectorTest.java (revision 0)
+++ src/test/java/org/apache/tika/language/LanguageDetectorTest.java (revision 0)
@@ -0,0 +1,76 @@
+package org.apache.tika.language;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tika.io.IOUtils;
+
+public abstract class LanguageDetectorTest {
+
+ protected String[] getTestLanguages() throws IOException {
+ List result = new ArrayList<>();
+
+ List lines = IOUtils.readLines(LanguageDetector.class.getResourceAsStream("language-codes.txt"));
+ for (String line : lines) {
+ line = line.trim();
+ if (line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
+
+ String[] parsed = line.split("\t");
+ String language = parsed[0];
+ if (hasTestLanguage(language)) {
+ result.add(language);
+ }
+ }
+
+ return result.toArray(new String[result.size()]);
+ }
+
+
+ protected boolean hasTestLanguage(String language) {
+ InputStream stream = LanguageDetectorTest.class.getResourceAsStream(language + ".test");
+ if (stream != null) {
+ IOUtils.closeQuietly(stream);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected void writeTo(String language, Writer writer) throws IOException {
+ writeTo(language, writer, Integer.MAX_VALUE);
+ }
+
+ protected void writeTo(String language, Writer writer, int limit) throws IOException {
+ InputStream stream = LanguageDetectorTest.class.getResourceAsStream(language + ".test");
+
+ try {
+ copyAtMost(new InputStreamReader(stream, UTF_8), writer, limit);
+ } finally {
+ stream.close();
+ }
+ }
+
+ protected int copyAtMost(Reader input, Writer output, int limit) throws IOException {
+ char[] buffer = new char[4096];
+ int count = 0;
+ int n = 0;
+
+ while ((-1 != (n = input.read(buffer))) && (count < limit)) {
+ int bytesToCopy = Math.min(limit - count, n);
+ output.write(buffer, 0, bytesToCopy);
+ count += bytesToCopy;
+ }
+
+ return count;
+ }
+
+}
Index: src/test/java/org/apache/tika/language/LanguageNamesTest.java
===================================================================
--- src/test/java/org/apache/tika/language/LanguageNamesTest.java (revision 0)
+++ src/test/java/org/apache/tika/language/LanguageNamesTest.java (revision 0)
@@ -0,0 +1,22 @@
+package org.apache.tika.language;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class LanguageNamesTest {
+
+ @Test
+ public void test() {
+
+ // macro language + language == language
+ String languageA = LanguageNames.normalizeName("zh-yue");
+ String languageB = LanguageNames.normalizeName("yue");
+ assertTrue(LanguageNames.equals(languageA, languageB));
+
+ // TODO verify that "en-Latn" == "en"
+
+ // TODO verify that "en-GB" == "en"???
+ }
+
+}
Index: src/test/java/org/apache/tika/language/OptimaizeLangDetectorTest.java
===================================================================
--- src/test/java/org/apache/tika/language/OptimaizeLangDetectorTest.java (revision 0)
+++ src/test/java/org/apache/tika/language/OptimaizeLangDetectorTest.java (revision 0)
@@ -0,0 +1,176 @@
+package org.apache.tika.language;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.tika.language.LanguageDetector;
+import org.apache.tika.language.LanguageResult;
+import org.apache.tika.language.LanguageWriter;
+import org.junit.Test;
+
+public class OptimaizeLangDetectorTest extends LanguageDetectorTest {
+
+ /*
+ * The complete list of supported languages (as of 0.5) is below.
+ * The ones we have tests for have '*' after the name.
+ *
+ af Afrikaans
+ an Aragonese
+ ar Arabic
+ ast Asturian
+ be Belarusian
+ br Breton
+ ca Catalan
+ bg Bulgarian
+ bn Bengali
+ cs Czech
+ cy Welsh
+ da Danish *
+ de German *
+ el Greek *
+ en English *
+ es Spanish *
+ et Estonian
+ eu Basque
+ fa Persian
+ fi Finnish *
+ fr French *
+ ga Irish
+ gl Galician
+ gu Gujarati
+ he Hebrew
+ hi Hindi
+ hr Croatian
+ ht Haitian
+ hu Hungarian
+ id Indonesian
+ is Icelandic
+ it Italian *
+ ja Japanese *
+ km Khmer
+ kn Kannada
+ ko Korean
+ lt Lithuanian *
+ lv Latvian
+ mk Macedonian
+ ml Malayalam
+ mr Marathi
+ ms Malay
+ mt Maltese
+ ne Nepali
+ nl Dutch *
+ no Norwegian
+ oc Occitan
+ pa Punjabi
+ pl Polish
+ pt Portuguese *
+ ro Romanian
+ ru Russian
+ sk Slovak
+ sl Slovene
+ so Somali
+ sq Albanian
+ sr Serbian
+ sv Swedish *
+ sw Swahili
+ ta Tamil
+ te Telugu
+ th Thai *
+ tl Tagalog
+ tr Turkish
+ uk Ukrainian
+ ur Urdu
+ vi Vietnamese
+ yi Yiddish
+ zh-CN Simplified Chinese * (just generic Chinese)
+ zh-TW Traditional Chinese * (just generic Chinese)
+ */
+
+ @Test
+ public void testAllLanguages() throws IOException {
+ LanguageDetector detector = new OptimaizeLangDetector();
+ detector.loadModels();
+
+ LanguageWriter writer = new LanguageWriter(detector);
+
+ for (String language : getTestLanguages()) {
+ writer.reset();
+
+ writeTo(language, writer);
+
+ LanguageResult result = detector.detect();
+ assertNotNull(result);
+
+ assertTrue(result.isLanguage(language));
+ assertTrue(result.isReasonablyCertain());
+ }
+ }
+
+ @Test
+ public void testMixedLanguages() throws IOException {
+ LanguageDetector detector = new OptimaizeLangDetector()
+ .setMixedLanguages(true);
+
+ detector.loadModels();
+ LanguageWriter writer = new LanguageWriter(detector);
+
+ String[] languages = getTestLanguages();
+ for (int i = 0; i < languages.length; i++) {
+ String language = languages[i];
+ for (int j = i + 1; j < languages.length; j++) {
+ String other = languages[j];
+
+ writer.reset();
+ writeTo(language, writer);
+ writeTo(other, writer);
+
+ List results = detector.detectAll();
+ if (results.size() > 0) {
+ LanguageResult result = results.get(0);
+
+ assertFalse("mix of " + language + " and " + other + " incorrectly detected as " + result, result.isReasonablyCertain());
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testShortText() throws IOException {
+ LanguageDetector detector = new OptimaizeLangDetector()
+ .setShortText(true)
+ .loadModels();
+
+ // First verify that we get no result with empty or very short text.
+ LanguageWriter writer = new LanguageWriter(detector);
+ writer.append("");
+ assertNull(detector.detect());
+
+ writer.reset();
+ writer.append(" ");
+ assertNull(detector.detect());
+
+ for (String language : getTestLanguages()) {
+ // Short pieces of Japanese are detected as Chinese
+ if (language.equals("ja")) {
+ continue;
+ }
+
+ // We need at least 300 characters to detect Chinese reliably.
+ writer.reset();
+ writeTo(language, writer, 300);
+
+ LanguageResult result = detector.detect();
+ assertNotNull(String.format("Language '%s' wasn't detected", language), result);
+
+ assertTrue(String.format("Language '%s' was detected as '%s'", language, result.getLanguage()), result.isLanguage(language));
+ assertTrue(String.format("Language '%s' isn't reasonably certain: %f", language, result.getConfidence()), result.isReasonablyCertain());
+ }
+ }
+
+
+}
Index: src/test/resources/org/apache/tika/language/ja.test
===================================================================
--- src/test/resources/org/apache/tika/language/ja.test (revision 0)
+++ src/test/resources/org/apache/tika/language/ja.test (revision 0)
@@ -0,0 +1,78 @@
+フィンセント・ファン・ゴッホ[注釈 1](Vincent Willem van Gogh、1853年3月30日 - 1890年7月29日)は、オランダ出身でポスト印象派(後期印象派)の画家。主要作品の多くは1886年以降のフランス居住時代、特にアルル時代(1888年 - 1889年5月)とサン=レミの精神病院での療養時代(1889年5月 - 1890年5月)に制作された。
+
+彼の作品は感情の率直な表現、大胆な色使いで知られ、ポスト印象派の代表的画家である。フォーヴィスムやドイツ表現主義など、20世紀の美術にも大きな影響を及ぼした。
+
+概要
+グーピル商会の画廊で働いていた19歳頃の写真[1]。
+1878年(当時21歳)のテオ。兄フィンセントの支援者・理解者であった。
+
+ゴッホは、1853年、オランダ南部のズンデルトで牧師の家に生まれた(→出生、少年時代)。1869年、画商グーピル商会に勤め始め、ハーグ、ロンドン、パリで働くが、1876年、商会を解雇された(→グーピル商会)。その後イギリスで教師として働いたりオランダのドルトレヒトの書店で働いたりするうちに聖職者を志すようになり、1877年、アムステルダムで神学部の受験勉強を始めるが挫折した。1878年末以降、ベルギーの炭坑地帯ボリナージュ地方で伝道活動を行ううち、画家を目指すことを決意した(→聖職者への志望)。以降、オランダのエッテン(1881年4月-12月)、ハーグ(1882年1月-1883年9月)、ニューネン(1883年12月-1885年11月)、ベルギーのアントウェルペン(1885年11月-1886年2月)と移り、弟テオドルス(通称テオ)の援助を受けながら画作を続けた。オランダ時代には、貧しい農民の生活を描いた暗い色調の絵が多く、ニューネンで制作した「ジャガイモを食べる人々」はこの時代の主要作品である。
+
+1886年2月、テオを頼ってパリに移り、印象派や新印象派の影響を受けた明るい色調の絵を描くようになった。この時期の作品としては「タンギー爺さん」などが知られる。日本の浮世絵にも関心を持ち、収集や模写を行っている(→パリ時代)。1888年2月、南フランスのアルルに移り、「ひまわり」や「夜のカフェテラス」などの名作を次々に生み出した。南フランスに画家の協同組合を築くことを夢見て、同年10月末からポール・ゴーギャンを迎えての共同生活が始まったが、次第に2人の関係は行き詰まり、12月末のゴッホの「耳切り事件」で共同生活は終焉した。以後、発作に苦しみながらアルルの病院への入退院を繰り返した(→アルル時代)。1889年5月からはアルル近郊のサン=レミの精神病院に入院した。発作の合間にも「星月夜」など多くの風景画、人物画を描き続けた(→サン=レミ時代)。1890年5月、精神病院を退院してパリ近郊のオーヴェル=シュル=オワーズに移り画作を続けたが(→オーヴェル時代)、7月27日、自ら銃を撃ち、29日死亡した。もっとも、自殺という一般の理解に対しては異説もある(→死)。発作等の原因については、癲癇、統合失調症など様々な仮説が研究者によって発表されている(→病因)。
+
+生前に売れた絵はたった1枚「赤い葡萄畑」だったと言われているが、晩年には彼を高く評価する評論が現れていた。彼の死後、回顧展の開催、書簡集や伝記の出版などを通じて急速に知名度が上がるにつれ、市場での作品の評価も急騰した。彼の生涯は多くの伝記や『炎の人ゴッホ』に代表される小説・映画などで描かれ、「情熱的な画家」、「狂気の天才」といった幻想的イメージをもって語られるようになった(→後世)。
+
+弟テオや友人らと交わした多くの手紙が、書簡集として出版されており、彼の生活や考え方を知ることができる(→手紙)。約10年の間に、油絵約860点、水彩画約150点、素描約1030点、版画約10点を残し、手紙に描き込んだスケッチ約130点も合わせると、2100以上の絵を残した[2]。有名な作品の多くは最後の2年間(アルル時代以降)に制作された油絵である。一連の「自画像」のほか身近な人々の肖像画、花の静物画、風景画などが多く、特に「ひまわり」や小麦畑、糸杉などをモチーフとしたものがよく知られている。印象派の美学の影響を受けながらも、大胆な色彩やタッチによって自己の内面や情念を表現した彼の作品は、外界の光の効果を画面上に捉えることを追求した印象派とは一線を画するものであり、ゴーギャンやセザンヌと並んでポスト印象派を代表する画家である。またその芸術は表現主義の先駆けでもあった(→作品)。
+
+生涯
+出生、少年時代(1853年-1869年)
+フィンセント・ファン・ゴッホは、1853年3月30日、オランダ南部の北ブラバント州ブレダにほど近いズンデルト[注釈 2]の村で、父テオドルス・ファン・ゴッホ(通称ドルス、1822年-1885年)と母アンナ・コルネリア・カルベントゥス(1819年-1907年)との間の長男として生まれた。父ドルスは、オランダ改革派の牧師であり、1849年にこの村の牧師館に赴任し、1851年、アンナと結婚した[3]。ブラバントは、オランダ北部とは異なりカトリックの人口が多く、ドルス牧師の指導する新教徒は村の少数派であった[4][注釈 3]。
+
+フィンセントという名は、ドルス牧師の父でブレダの高名な牧師であったフィンセント・ファン・ゴッホ(1789年-1874年)からとられている[5]。祖父フィンセントには、長男ヘンドリク(ヘイン伯父)、次女ドロアテ、次男ヨハンネス(ヤン伯父)、三男ヴィレム、四男フィンセント(セント伯父)、五男テオドルス(父ドルス牧師)、三女エリーザベト、六男コルネリス・マリヌス(コル叔父)、四女マリアという子があり、このうちヘイン伯父、セント伯父、コル叔父は画商になっている[6]。
+1866年頃(13歳頃)のフィンセント。
+「農場の家と納屋」1864年2月、素描。
+
+父ドルス牧師と母アンナとの間には、画家フィンセントが生まれるちょうど1年前の1852年3月30日に、死産の子があり、その兄にもフィンセントという名が付けられていた[7][注釈 4]。画家フィンセントの後に、妹アンナ(1855年生)、弟テオドルス(通称テオ、1857年生)、妹エリーザベト(1859年生)、妹ヴィレミーナ(通称ヴィル、1862年生)、弟コルネリス(通称コル、1867年生)が生まれた[8]。
+
+フィンセントは、小さい時から癇癪持ちで、両親や家政婦からは兄弟の中でもとりわけ扱いにくい子と見られていた。親に無断で一人で遠出することも多く、ヒースの広がる低湿地を歩き回り、花や昆虫や鳥を観察して1日を過ごしていた[9]。1860年からズンデルト村の学校に通っていたが、1861年から1864年まで、妹アンナとともに家庭教師の指導を受けた[8]。1864年2月に11歳のフィンセントが父の誕生日のために描いたと思われる「農場の家と納屋」と題する素描が残っており、絵の才能の可能性を示している[10]。1864年10月からは約20km離れたゼーフェンベルゲンのヤン・プロフィリ寄宿学校に入った[8]。彼は、後に、親元を離れて入学した時のことを「僕がプロフィリさんの学校の石段の上に立って、お父さんとお母さんを乗せた馬車が家の方へ帰っていくのを見送っていたのは、秋の日のことだった。」と回顧している[11][手紙 1]。
+
+1866年9月15日、ティルブルフに新しくできた国立高等市民学校、ウィレム2世校に進学した。パリで成功したコンスタント=コルネーリス・ハイスマンスという画家がこの学校で教えており、ゴッホも彼から絵を習ったと思われる[12]。1868年3月、ゴッホはあと1年を残して学校をやめ、家に帰ってしまった。その理由は分かっていない[13]。本人は、1883年テオに宛てた手紙の中で、「僕の若い時代は、陰鬱で冷たく不毛だった」と書いている[手紙 2]。
+グーピル商会(1869年-1876年)
+
+1869年7月、セント伯父の助力で、ゴッホは画商グーピル商会のハーグ支店の店員となり、ここで約4年間過ごした[注釈 5]。彼は、この時のことについて「2年間は割と面白くなかったが、最後の年はとても楽しかった」と書いている[14][手紙 3]。テオの妻ヨーによれば、この時上司のテルステーフはフィンセントの両親に、彼は勤勉で誰にも好かれるという高評価を書き送ったというが[15]、実際にはテルステーフやハーグ支店の経営者であるセント伯父との関係はうまく行っていなかったと見られる[16]。1872年夏、当時まだ学生だった弟テオがハーグのフィンセントのもとを訪れ、職場でも両親との間でも孤立感を深めていたフィンセントはテオに親しみを見出した。この時レイスウェイクまで2人で散歩し、にわか雨に遭って風車小屋でミルクを飲んだことを、フィンセントは後に鮮やかな思い出として回想している。この直後にフィンセントはテオに手紙を書き、以後2人の間で書簡のやり取りが始まった[17]。
+ゴッホが1869年(16歳)から1873年(20歳)まで勤めたグーピル商会ハーグ支店。
+
+フィンセントは、ハーグ支店時代に、近くのマウリッツハイス美術館でレンブラントやフェルメールらオランダ黄金時代の絵画に触れるなど、美術に興味を持つようになった。また、グーピル商会で1870年代初頭から扱われるようになった新興のハーグ派の絵にも触れる機会があった[18]。
+
+1873年5月、彼はロンドン支店に転勤となった[19]。表向きは栄転であったが、実際にはテルステーフやセント伯父との関係悪化、フィンセントの娼館通いなどの不品行が理由でハーグを追い出されたものとも見られている[20]。8月末からロワイエ家の下宿に移った[21]。ヨーの回想録によれば、ゴッホは下宿先の娘ユルシュラ・ロワイエに恋をし、思いを告白したが、彼女は実は以前下宿していた男と婚約していると言って断られたという。そして、その後彼はますます孤独になり、宗教的情熱を強めることになったという[22]。しかし、この物語には最近の研究で疑問が投げかけられており、ユルシュラは下宿先の娘ではなくその母親の名前であることが分かっている[注釈 6]。そして、ゴッホ自身が書いている「20歳の恋」[注釈 7]の相手は、ハーグで親交のあった遠い親戚のカロリーナ・ファン・ストックム=ハーネベーク(カロリーン)ではないかという説がある[23]。いずれにしても、彼は、ロワイエ家の下宿を出た後、1874年冬頃から、チャールズ・スポルジョンの説教を聞きに行ったり、ジュール・ミシュレ、イポリット・テーヌの著作、またエルネスト・ルナンの『イエス伝』などを読み進めたりするうちに、キリスト教への関心を急速に深めていった[24]。
+
+1875年5月、彼はパリ本店に転勤となった[25][注釈 8]。同じパリ本店の見習いで同宿だったハリー・グラッドウェルとともに、聖書やトマス・ア・ケンピスの『キリストに倣いて』に読みふけった[26]。他方、金儲けだけを追求するようなグーピル商会の仕事には反感を募らせた[27]。この頃、父はフィンセントには今の職場が合わないようだとテオに書いている[28]。翌1876年1月、彼はグーピル商会から4月1日をもって解雇するとの通告を受けた[29][手紙 4][注釈 9]。この事件は両親に衝撃と失望を与えた[30]。
+聖職者への志望(1876年-1880年)
+「エッテンの牧師館と教会」1876年4月、エッテン。グーピル商会を解雇された23歳のゴッホは、イギリスに発つ前、ブレダ西郊の農村エッテンの実家に立ち寄り、家族に別れを告げた[31][注釈 10]。
+
+同年(1876年)4月、ゴッホはイギリスに戻り、ラムズゲートの港を見下ろす、ストークス氏の経営する小さな寄宿学校で無給で教師として働くこととなった。ここで少年たちにフランス語初歩、算術、書き取りなどを教えた。同年6月、寄宿学校はロンドン郊外のアイズルワースに移ることとなり、フィンセントはアイズルワースまで徒歩で旅した。しかし、伝道師になって労働者や貧しい人の間で働きたいという希望を持っていたフィンセントは、ストークス氏の寄宿学校での仕事を続けることなく、組合教会のジョーンズ牧師の下で、少年たちに聖書を教えたり、貧民街で牧師の手伝いをしたりした[32]。ジョージ・エリオットの『牧師館物語』や『アダム・ビード』を読んだことも、伝道師になりたいという希望に火を付けた[33]。
+
+その年のクリスマス、彼はエッテンの父の家に帰省した。聖職者になるには7年から8年もの勉強が必要であり、無理だという父ドルス牧師の説得を受け[34]、翌1877年1月から5月初旬まで、南ホラント州ドルトレヒトの書店ブリュッセ&ファン・ブラームで働いた。しかし、言われた仕事は果たすものの、暇を見つけては聖書の章句を英語やフランス語やドイツ語に翻訳していたという。また、この時の下宿仲間で教師だったヘルリッツは、フィンセントは食卓で長い間祈り、肉は口にせず、日曜日にはオランダ改革派教会だけでなくヤンセン派教会、カトリック教会、ルター派教会に行っていたと語っている[35]。
+
+フィンセントは、ますます聖職者になりたいという希望を募らせ、受験勉強に耐えることを約束して父を説得した[36]。同年3月、アムステルダムのコル叔父や、母の姉の夫ヨハネス・ストリッケル牧師を訪ねて、相談した。コル叔父の仲介で、アムステルダム海軍造船所長官のヤン伯父が、ゴッホの神学部受験のため、彼を迎え入れてくれることになった。そして、同年5月、ゴッホはエッテンからアムステルダムに向かい、ヤン伯父の家に下宿し、ストリッケル牧師と相談しながら、王立大学での神学教育を目指して勉学に励むことになった[37]。ストリッケル牧師の世話で、2歳年上のメンデス・ダ・コスタからギリシャ語とラテン語を習った。しかし、その複雑な文法や、代数、幾何、歴史、地理、オランダ語文法など受験科目の多さに挫折を味わった[38]。精神的に追い詰められたゴッホは、パンしか口にしない、わざと屋外で夜を明かす、杖で自分の背中を打つというような自罰的行動に走った[39]。1878年2月、習熟度のチェックのために訪れた父からは、勉強が進んでいないことを厳しく指摘され、学資も自分で稼ぐように言い渡された[40]。フィンセントはますます勉強から遠ざかり、アムステルダムでユダヤ人にキリスト教を布教しようとしているチャールズ・アドラー牧師らと交わるうちに、貧しい人々に聖書を説く伝道師になりたいという思いを固めた[41]。
+
+こうして、同年(1878年)10月の試験の日を待たずに、同年7月、ヤン伯父の家を出てエッテンに戻り、今度は同年8月からベルギーのブリュッセル北郊ラーケンの伝道師養成学校で3か月間の試行期間を過ごした。同年11月15日に試行期間が終わる時、学校から、フランドル生まれの生徒と同じ条件での在学はできない、ただし無料で授業を受けてもよい、という提案を受けた。しかし、彼は、引き続き勉強するためには資金が必要だから、自分は伝道のためボリナージュに行くことにするとテオに書いている[42][手紙 5]。
+
+同年(1878年)12月、彼はベルギーの炭鉱地帯、ボリナージュ地方(モンス近郊)に赴き、プティ=ヴァムの村で、パン屋ジャン=バティスト・ドゥニの家に下宿しながら伝道活動を始めた。1879年1月から、熱意を認められて半年の間は伝道師としての仮免許と月額50フランの俸給が与えられることになった。彼は貧しい人々に説教を行い、病人・けが人に献身的に尽くすとともに、自分自身も貧しい坑夫らの生活に合わせて同じような生活を送るようになり、着るものもみすぼらしくなった[43]。しかし、苛酷な労働条件や賃金の大幅カットに労働者が死に、抑圧され、労働争議が巻き起こる炭鉱の町において、社会的不正義に憤るというよりも、『キリストに倣いて』が教えるように、苦しみの中に神の癒しを見出すことを説いたオランダ人伝道師は、人々の理解を得られなかった[44]。教会の伝道委員会も、ゴッホの常軌を逸した自罰的行動を伝道師の威厳を損なうものとして否定し、ゴッホがその警告に従うことを拒絶すると、伝道師の仮免許と俸給は打ち切られた[45]。
+1880年、ゴッホ(当時27歳)がクウェムで暮らした家。ここにいる時に彼は画家となることを決めた。
+
+伝道師としての道を絶たれたゴッホは、同年(1879年)8月、同じくボリナージュ地方のクウェム(モンス南西の郊外)の伝道師フランクと坑夫シャルル・ドゥクリュクの家に移り住んだ[46]。父親からの仕送りに頼ってデッサンの模写や坑夫のスケッチをして過ごしたが、家族からは仕事をしていないフィンセントに厳しい目が注がれ、彼のもとを訪れた弟テオからも「年金生活者」のような生活ぶりについて批判された[47]。1880年3月頃、絶望のうちに北フランスへ放浪の旅に出て、金も食べるものも泊まるところもなく、ひたすら歩いて回った[48]。そしてついにエッテンの実家に帰ったが、彼の常軌を逸した傾向を憂慮した父親がヘールの精神病院に入れようとしたことで口論になり、クウェムに戻った[49]。
+
+クウェムに戻った1880年6月頃から、テオからフィンセントへの生活費の援助が始まった[50][手紙 6]。また、この時期、周りの人々や風景をスケッチしているうちに、ゴッホは本格的に絵を描くことを決意したようである[51]。9月には、北フランスへの苦しい放浪を振り返って、「しかしまさにこの貧窮の中で、僕は力が戻ってくるのを感じ、ここから立ち直るのだ、くじけて置いていた鉛筆をとり直し、絵に戻るのだと自分に言い聞かせた。」と書いている[手紙 7]。ジャン=フランソワ・ミレーの複製を手本に素描を練習したり、シャルル・バルグのデッサン教本を模写したりした[52]。
+
+同年(1880年)10月、絵を勉強しようとして突然ブリュッセルに出て行った。そして、運搬夫、労働者、少年、兵隊などをモデルにデッサンを続けた。また、この時、ブリュッセル王立美術アカデミーに在籍していた画家アントン・ファン・ラッパルトと交友を持つようになった[53]。ゴッホ自身も、ハーグ派の画家ウィレム・ルーロフスから、本格的に画家を目指すのであればアカデミーに進むよう勧められた[54]。同年11月第1週から、同アカデミーの「アンティーク作品からの素描」というコースに登録した記録が残っており、実際に短期間出席したものと見られている[55]。また、名前は不明だが、ある画家から短期間、遠近法や解剖学のレッスンを受けていた[56]。
+オランダ時代
+エッテン(1881年)
+「父テオドルス」1881年、エッテン。鉛筆。
+ゴッホ(当時27歳)の片思いの相手ケー・フォス・ストリッケルと、その息子ヤン。
+
+1881年4月、ゴッホはブリュッセルに住むことによる経済的な問題が大きかったため、エッテンの実家に戻り、田園風景や近くの農夫たちを素材に素描や水彩画を描き続けた。まだぎこちなさが残るが、この頃にはゴッホ特有の太く黒い描線と力強さが現れ始めていた[57]。夏の間、最近夫を亡くしたいとこのケー・フォス・ストリッケル(母の姉と、アムステルダムのヨハネス・ストリッケル牧師との間の娘)がエッテンを訪れた。彼はケーと連れ立って散歩したりするうちに、彼女に好意を持つようになった。未亡人のケーはゴッホより7歳上で、さらに8歳の子供もいたにもかかわらずゴッホは求婚するが、「とんでもない、だめ、絶対に。」という言葉で拒絶され、打ちのめされた[58][手紙 8]。
+
+ケーはアムステルダムに帰ってしまったが、ゴッホは彼女への思いを諦めきれず、ケーに何度も手紙を書き、11月末には、テオに無心した金でアムステルダムのストリッケル牧師の家を訪ねた。しかし、ケーからは会うことを拒否され、両親のストリッケル夫妻からはしつこい行動が不愉快だと非難された。絶望した彼は、ストリッケル夫妻の前でランプの炎に手をかざし、「私が炎に手を置いていられる間、彼女に会わせてください。」と迫ったが、夫妻は、ランプを吹き消して、会うことはできないと言うのみだった[59][手紙 9]。伯父ストリッケル牧師の頑迷な態度は、ゴッホに聖職者たちへの疑念を呼び起こし、父やストリッケル牧師の世代との溝を強く意識させることになった[60]。
+
+11月27日、ハーグに向かい、義理の従兄弟で画家のアントン・モーヴから絵の指導を受けたが、クリスマス前にいったんエッテンの実家に帰省する。しかし、クリスマスの日に彼は教会に行くことを拒み、それが原因で父親と激しく口論し、その日のうちに実家を離れて再びハーグへ発ってしまった[61][手紙 10]。
+ハーグ(1882年-1883年)
+「屋根、ハーグのアトリエからの眺め」1882年、ハーグ。水彩。個人コレクション。ゴッホは28歳から30歳にかけてハーグに住んだ。
+シーンを描いた「悲しみ」1882年4月、ハーグ。素描(黒チョーク)。
+
+1882年1月、彼はハーグに住み始め、オランダ写実主義・ハーグ派の担い手であったモーヴを頼った。モーヴはゴッホに油絵と水彩画の指導をするとともに、アトリエを借りるための資金を貸し出すなど、親身になって面倒を見てくれた[62]。ハーグの絵画協会プルクリ・スタジオの準会員にも推薦してくれた[63]。しかし、モーヴは次第にゴッホによそよそしい態度を取り始め、ゴッホが手紙を書いても返事を寄越さなくなった。ゴッホはこの頃にクラシーナ・マリア・ホールニク(通称シーン)という身重の娼婦をモデルとして使いながら、彼女の家賃を払ってやるなどの援助をしており、結婚さえ考えていたが、彼は、モーヴの態度が冷たくなったのはこの交際のためだと考えている[64][手紙 11]。石膏像のスケッチから始めるよう助言するモーヴと、モデルを使っての人物画に固執するゴッホとの意見の不一致も原因のようである[65]。ゴッホは、わずかな意見の違いも自分に対する全否定であるかのように受け止めて怒りを爆発させる性向があり、モーヴに限らず、知り合ったハーグ派の画家たちも次々彼を避けるようになっていった[66]。交友関係に失敗した彼の関心は、アトリエでモデルに思いどおりのポーズをとらせ、ひたすらスケッチをすることに集中したが、月100フランのテオからの仕送りの大部分をモデル料に費やし、少しでも送金が遅れると自分の芸術を損なうものだと言ってテオをなじった[67][注釈 11]。
+1882年夏頃、遠近法やプロポーションを捉えるための透視枠を自作し、1888年5月のアルル初期まで使っていた[68][手紙 12]。
+
+同年(1882年)3月、ゴッホのもとを訪れたコル叔父が、街の風景の素描を12点注文してくれたため、ゴッホはハーグ市街を描き続けた[69]。そしてコル叔父に素描を送ったが、コル叔父は「こんなのは商品価値がない」と言って、ゴッホが期待したほどの代金は送ってくれなかった[70]。ゴッホは、同年6月、淋病で3週間入院し、退院直後の7月始め、ゴッホは今までの家の隣の家に引っ越し、この新居に、長男ウィレムを出産したばかりのシーンとその5歳の娘と暮らし始めた[71]。一時は、売れる見込みのある油絵の風景画を描くようにとのテオの忠告にしぶしぶ従い、スヘフェニンゲンの海岸などを描いたが、間もなく、上達が遅いことを自ら認め、挫折した[72]。冬の間は、アトリエで、シーンの母親や、赤ん坊、身寄りのない老人などを素描した[73]。
+
+ゴッホはそこで1年余りシーンと共同生活をしていたが、1883年5月には、「シーンはかんしゃくを起こし、意地悪くなり、とても耐え難い状態だ。以前の悪習へ逆戻りしそうで、こちらも絶望的になる。」などとテオに書いている[74][手紙 13]。ゴッホは、オランダ北部のドレンテ州に出て油絵の修行をすることを考え、同年9月初め、シーンとの間で、ハーグでこのまま暮らすことは経済的に不可能であるため、彼女は子どもたちを自分の家族に引き取ってもらうこと、彼女は自分の仕事を探すことなどを話し合った。シーンと別れたことを父に知らせ、ゴッホは、9月11日、ドレンテ州のホーヘフェーンへ発った[75][手紙 14][注釈 12]。また、同年10月からはドレンテ州ニーウ・アムステルダムの泥炭地帯を旅しながら、ミレーのように農民の生活を描くべきだと感じ、馬で畑を犂く人々を素描した[76]。
Index: src/test/resources/org/apache/tika/language/language-codes.txt
===================================================================
--- src/test/resources/org/apache/tika/language/language-codes.txt (revision 0)
+++ src/test/resources/org/apache/tika/language/language-codes.txt (revision 0)
@@ -0,0 +1,186 @@
+# From https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+
+aa Afar
+ab Abkhaz
+ae Avestan
+af Afrikaans
+ak Akan
+am Amharic
+an Aragonese
+ar Arabic
+as Assamese
+av Avaric
+ay Aymara
+az Azerbaijani
+ba Bashkir
+be Belarusian
+bg Bulgarian
+bh Bihari
+bi Bislama
+bm Bambara
+bn Bengali, Bangla
+bo Tibetan Standard, Tibetan, Central
+br Breton
+bs Bosnian
+ca Catalan
+ce Chechen
+ch Chamorro
+co Corsican
+cr Cree
+cs Czech
+cu Old Church Slavonic, Church Slavonic, Old Bulgarian
+cv Chuvash
+cy Welsh
+da Danish
+de German
+dv Divehi, Dhivehi, Maldivian
+dz Dzongkha
+ee Ewe
+el Greek (modern)
+en English
+eo Esperanto
+es Spanish
+et Estonian
+eu Basque
+fa Persian (Farsi)
+ff Fula, Fulah, Pulaar, Pular
+fi Finnish
+fj Fijian
+fo Faroese
+fr French
+fy Western Frisian
+ga Irish
+gd Scottish Gaelic, Gaelic
+gl Galician
+gn Guaraní
+gu Gujarati
+gv Manx
+ha Hausa
+he Hebrew (modern)
+hi Hindi
+ho Hiri Motu
+hr Croatian
+ht Haitian, Haitian Creole
+hu Hungarian
+hy Armenian
+hz Herero
+ia Interlingua
+id Indonesian
+ie Interlingue
+ig Igbo
+ii Nuosu
+ik Inupiaq
+io Ido
+is Icelandic
+it Italian
+iu Inuktitut
+ja Japanese
+jv Javanese
+ka Georgian
+kg Kongo
+ki Kikuyu, Gikuyu
+kj Kwanyama, Kuanyama
+kk Kazakh
+kl Kalaallisut, Greenlandic
+km Khmer
+kn Kannada
+ko Korean
+kr Kanuri
+ks Kashmiri
+ku Kurdish
+kv Komi
+kw Cornish
+ky Kyrgyz
+la Latin
+lb Luxembourgish, Letzeburgesch
+lg Ganda
+li Limburgish, Limburgan, Limburger
+ln Lingala
+lo Lao
+lt Lithuanian
+lu Luba-Katanga
+lv Latvian
+mg Malagasy
+mh Marshallese
+mi Māori
+mk Macedonian
+ml Malayalam
+mn Mongolian
+mr Marathi (Marāṭhī)
+ms Malay
+mt Maltese
+my Burmese
+na Nauru
+nb Norwegian Bokmål
+nd Northern Ndebele
+ne Nepali
+ng Ndonga
+nl Dutch
+nn Norwegian Nynorsk
+no Norwegian
+nr Southern Ndebele
+nv Navajo, Navaho
+ny Chichewa, Chewa, Nyanja
+oc Occitan
+oj Ojibwe, Ojibwa
+om Oromo
+or Oriya
+os Ossetian, Ossetic
+pa Panjabi, Punjabi
+pi Pāli
+pl Polish
+ps Pashto, Pushto
+pt Portuguese
+qu Quechua
+rm Romansh
+rn Kirundi
+ro Romanian
+ru Russian
+rw Kinyarwanda
+sa Sanskrit (Saṁskṛta)
+sc Sardinian
+sd Sindhi
+se Northern Sami
+sg Sango
+si Sinhala, Sinhalese
+sk Slovak
+sl Slovene
+sm Samoan
+sn Shona
+so Somali
+sq Albanian
+sr Serbian
+ss Swati
+st Southern Sotho
+su Sundanese
+sv Swedish
+sw Swahili
+ta Tamil
+te Telugu
+tg Tajik
+th Thai
+ti Tigrinya
+tk Turkmen
+tl Tagalog
+tn Tswana
+to Tonga (Tonga Islands)
+tr Turkish
+ts Tsonga
+tt Tatar
+tw Twi
+ty Tahitian
+ug Uyghur
+uk Ukrainian
+ur Urdu
+uz Uzbek
+ve Venda
+vi Vietnamese
+vo Volapük
+wa Walloon
+wo Wolof
+xh Xhosa
+yi Yiddish
+yo Yoruba
+za Zhuang, Chuang
+zh Chinese
+zu Zulu
Index: src/test/resources/org/apache/tika/language/th.test
===================================================================
--- src/test/resources/org/apache/tika/language/th.test (revision 0)
+++ src/test/resources/org/apache/tika/language/th.test (revision 0)
@@ -0,0 +1,28 @@
+สงครามอังกฤษ–แซนซิบาร์
+จากวิกิพีเดีย สารานุกรมเสรี
+สงครามอังกฤษ-แซนซิบาร์ (อังกฤษ: Anglo-Zanzibar War) เป็นการสู้รบระหว่างสหราชอาณาจักรและรัฐสุลต่านแซนซิบาร์ในวันที่ 27 สิงหาคม ค.ศ. 1896 ความขัดแย้งนี้กินเวลาเพียง 38 นาที[nb 1] นับเป็นสงครามที่สั้นที่สุดในประวัติศาสตร์[7] สาเหตุที่ใกล้ชิดของสงครามนี้เกิดจากฮาเม็ด บิน ทูเวไน (Hamad bin Thuwaini) สุลต่านที่ได้รับความเห็นชอบจากสหราชอาณาจักร สวรรคตในวันที่ 25 สิงหาคม ค.ศ. 1896 และคาลิด บิน บาร์กาช (Khalid bin Barghash) สืบราชสันตติวงศ์ ขณะที่สหราชอาณาจักรเห็นชอบให้ฮามัด บิน มุฮามเม็ด (Hamud bin Muhammed) ผู้ที่จะอำนวยประโยชน์ให้แก่สหราชอาณาจักรได้มากกว่า เป็นสุลต่าน ตามสนธิสัญญาที่ลงนามใน ค.ศ. 1886 เงื่อนไขการขึ้นครองราชย์ คือ ผู้มีคุณสมบัติต้องได้รับการอนุญาตจากกงสุลสหราชอาณาจักรเสียก่อน แต่คาลิดนั้นมิได้เป็นไปตามข้อกำหนดนี้ สหราชอาณาจักรถือว่าเป็นเหตุแห่งสงคราม และยื่นคำขาดต่อคาลิดให้พระองค์มีพระบรมราชโองการให้กองกำลังของพระองค์วางอาวุธ และให้ออกจากพระราชวัง สุลต่านคาลิดโต้ตอบโดยทรงระดมยามพระราชวังและทรงขังพระองค์อยู่ในพระราชวัง
+
+เส้นตายสิ้นสุดที่เวลา 09:00 น. ตามเวลาแอฟริกาตะวันออก (EAT) ของวันที่ 27 สิงหาคม ณ เวลานั้นกองกำลังของอังกฤษประกอบด้วยเรือลาดตระเวน 3 ลำ เรือปืน 2 ลำ นาวิกโยธินและลูกเรือ 150 นาย และชาวแซนซิบาร์ 900 คนได้ชุมนุมกันที่บริเวณท่าเรือ กองทัพเรือสหราชอาณาจักรอยู่ภายใต้บังคับบัญชาของพลเรือตรีแฮร์รี รอว์ซัน (Harry Rawson) ขณะที่ชาวแซนซิบาร์อยู่ภายใต้การบังคับบัญชาของพลจัตวาลอยด์ แมตทิวส์ (Lloyd Mathews) แห่งกองทัพบกแซนซิบาร์ กองกำลังป้องกันพระราชวังฝ่ายแซนซิบาร์มีประมาณ 2,800 คน กองกำลังส่วนมากเกณฑ์มาจากประชาชนทั่วไป มียามพระราชวังปะปนอยู่บ้าง และมีคนรับใช้และทาสของคาลิดอีกหลายร้อยคน ฝ่ายป้องกันมีปืนใหญ่สองสามกระบอกและปืนกลที่ติดตั้งอยู่หน้าพระราชวังโดยเล็งไปยังเรือของอังกฤษ การระดมยิงเปิดฉากเมื่อเวลา 09:02 น. ผลทำให้พระราชวังไฟไหม้และปืนใหญ่ฝ่ายตั้งรับไม่สามารถใช้การได้ มีการปฏิบัติทางเรือขนาดเล็ก โดยฝ่ายอังกฤษสามารถจมเรือยอตช์หลวงของแซนซิบาร์และเรือที่เล็กกว่าได้สองลำ มีการยิงมาที่ทหารแซนซิบาร์ที่นิยมอังกฤษบ้างขณะที่เคลื่อนเข้าสู่พระราชวัง แต่ไร้ผล ธงที่พระราชวังถูกยิงล้ม และการยิงสิ้นสุดลงเมื่อเวลา 09:40 น.
+
+กองกำลังของสุลต่านคาลิดมีกำลังพลสูญเสียประมาณ 500 คน ขณะที่ลูกเรืออังกฤษบาดเจ็บเพียงคนเดียว สุลต่านคาลิดเสด็จลี้ภัยไปยังกงสุลเยอรมนี ก่อนที่จะหลบหนีต่อไปยังแอฟริกาตะวันออกของเยอรมนี (ปัจจุบัน คือ ประเทศแทนซาเนียส่วนแผ่นดินใหญ่) อังกฤษตั้งฮามัดขึ้นเป็นสุลต่านอย่างรวดเร็วเพื่อเป็นผู้นำของรัฐบาลหุ่น สงครามยุติสถานะรัฐเอกราชของแซนซิบาร์และเริ่มต้นยุคที่อังกฤษเข้ามามีอิทธิพลอย่างสูง
+
+แซนซิบาร์เป็นประเทศบนเกาะในมหาสมุทรอินเดีย นอกชายฝั่งแทนแกนยิกา ปัจจุบันเป็นส่วนหนึ่งของประเทศแทนซาเนีย เกาะอยู่ภายใต้การปกครองแต่เพียงในนามของสุลต่านแห่งโอมานตั้งแต่ปี ค.ศ. 1698 เมื่อขับไล่ผู้ตั้งถิ่นฐานชาวโปรตุเกสผู้อ้างสิทธิ์ในเกาะในปี ค.ศ. 1499 ออกไป[8] สุลต่านฮาจีด บิน เซด (Majid bin Said) ประกาศอิสรภาพจากโอมานใน ค.ศ. 1858 ซึ่งการครั้งนี้บริเตนใหญ่ให้การรับรอง และแบ่งแยกรัฐสุลต่านออกจากโอมาน[8] ต่อมาสุลต่านทรงตั้งเมืองหลวงและทำเนียบรัฐบาลขึ้นที่แซนซิบาร์ทาวน์ อันเป็นที่ซึ่งมีการสร้างกลุ่มอาคารพระราชวังติดทะเล ในปี ค.ศ. 1896 กลุ่มอาคารพระราชวังนี้ประกอบด้วย บีต อัล ฮุก์ม (Beit al-Hukm) ฮาเร็มที่ติดกัน และ บีต อัล อาเจบ (Beit al-Ajaib) หรือ "House of Wonder (บ้านมหัศจรรย์)" พระราชวังอันใหญ่โตที่กล่าวกันว่าเป็นสิ่งก่อสร้างแรกในแอฟริกาตะวันออกที่มีไฟฟ้าใช้[9] กลุ่มอาคารส่วนใหญ่สร้างขึ้นจากไม้ท้องถิ่น และมิได้ถูกกำหนดมาให้เป็นสิ่งก่อสร้างเพื่อใช้ป้องกัน[10] อาคารหลังทั้งสามสร้างติดกันเป็นเส้นตรง และเชื่อมต่อกันด้วยสะพานไม้อยู่สูงเหนือถนน[11]
+
+อังกฤษมีปฏิสัมพันธ์ฉันมิตรกับแซนซิบาร์มาช้านาน และยอมรับอธิปไตยและรัฐสุลต่านในปี ค.ศ. 1886[8][12][13] และโดยทั่วไปธำรงความสัมพันธ์อันดีกับประเทศและสุลต่าน[8] อย่างไรก็ตาม เยอรมนีก็สนใจในแอฟริกาตะวันออกเช่นกัน และมหาอำนาจทั้งสองก็แข่งขันเพื่อควบคุมสิทธิการค้าและดินแดนในพื้นที่ตลอดปลายคริสต์ศตวรรษที่ 19[14] สุลต่านคาริฟฟาห์พระราชทานสิทธิในดินแดนเคนยาแก่อังกฤษและสิทธิในดินแดนแทนแกนยิกาแก่เยอรมนี อันส่งผลให้เกิดการเลิกระบบทาสในดินแดนเหล่านั้น[8] ชนชั้นปกครองชาวอาหรับจำนวนมากหัวเสียจากการรบกวนการค้าอันมีค่านี้ ซึ่งส่งผลให้เกิดความไม่สงบอยู่บ้าง[8] นอกจากนี้ ทางการเยอรมนีในแทนแกนยิกาปฏิเสธที่จะชักธงของรัฐสุลต่านแซนซิบาร์ขึ้น ซึ่งนำไปสู่การปะทะกันด้วยอาวุธระหว่างทหารเยอรมันและประชาชนท้องถิ่น[15] หนึ่งในความขัดแย้งในเมืองแทนกามีชาวอาหรับเสียชีวิต 20 คน[15]
+
+สุลต่านคาริฟฟาห์ทรงส่งทหารแซนซิบาร์นำโดยพลเอกลอยด์ แมตทิวส์ (Lloyd Mathews) อดีตเรือโทแห่งกองทัพเรืออังกฤษ ไปฟื้นฟูความสงบเรียบร้อยในแทนแกนยิกา[16] ปฏิบัติการนี้ประสบความสำเร็จอย่างมาก แต่ความรู้สึกต่อต้านเยอรมนีในหมู่ชาวแซนซิบาร์ยังแรงกล้าอยู่[15] ความขัดแย้งปะทุขึ้นอีกที่เมืองบากาโมโย (Bagamoyo) เมื่อชนพื้นเมือง 150 คนถูกทหารเยอรมันสังหาร และที่เคตวา (Ketwa) ที่ข้าราชการเยอรมนีและบ่าวถูกฆ่าตาย[16] สุลต่านคาริฟฟาห์พระราชทานสิทธิการค้ากว้างขวางแก่บริษัทแอฟริกาตะวันออกของจักรวรรดิอังกฤษ (IBEAC) ซึ่ง ด้วยความช่วยเหลือจากเยอรมนี ได้ปิดล้อมทางทะเลเพื่อหยุดการค้าทาสในประเทศที่ดำเนินต่อไป[16] เมื่อสุลต่านคาริฟฟาห์สวรรคตในปี ค.ศ. 1890 อะลี บิน ซัยด์ได้สืบราชบัลลังก์รัฐสุลต่าน[17] สุลต่านอะลีทรงห้ามการค้าทาสในประเทศ (แต่มิได้ทรงห้ามการเป็นเจ้าของทาส) ทรงประกาศให้แซนซิบาร์เป็นรัฐในอารักขาของอังกฤษและแต่งตั้งนายกรัฐมนตรีชาวอังกฤษให้นำคณะรัฐมนตรีในพระองค์ อังกฤษยังได้รับประกันการยับยั้งการแต่งตั้งสุลต่านในอนาคตด้วย[18]
+
+ปีที่สุลต่านอะลีสวรรคต มีการลงนามในสนธิสัญญาเฮลิโกแลนด์-แซนซิบาร์ระหว่างบริเตนและเยอรมนี สนธิสัญญานี้ปักปันเขตอิทธิพลในแอฟริกาตะวันออกและยกสิทธิของเยอรมนีในแซนซิบาร์ให้แก่สหราชอาณาจักร[19] ทำให้รัฐบาลอังกฤษมีอิทธิพลมากขึ้นในแซนซิบาร์ ซึ่งรัฐบาลอังกฤษตั้งใจใช้เพื่อกำจัดความเป็นทาสที่นั่น อันเป็นวัตถุประสงค์ที่ตั้งเป้าไว้มาตั้งแต่ปี ค.ศ. 1804[20][21]
+
+ฮาเม็ด บิน ทูเวไนเป็นสุลต่านสืบต่อจากสุลต่านอะลีในปี ค.ศ. 1893 สุลต่านฮาเม็ดรักษาความสัมพันธ์ที่ใกล้ชิดกับอังกฤษไว้ แต่กลับเกิดความไม่เห็นพ้องในบรรดาคนในบังคับของสุลต่านเรื่องการควบคุมของอังกฤษที่เพิ่มขึ้นทั่วประเทศ กองทัพที่นำโดยอังกฤษ และการเลิกการค้าทาสอันมีค่า[18] เพื่อควบคุมความไม่เห็นพ้องนี้ ทางการอังกฤษจึงอนุญาตให้สุลต่านตั้งองครักษ์พระราชวังชาวแซนซิบาร์จำนวน 1,000 นาย แต่ไม่นานองครักษ์เหล่านี้กลับเข้าไปปะทะกับตำรวจที่นำโดยอังกฤษ[22][23] นอกจากนี้ยังมีคำร้องทุกข์เกี่ยวกับกิจกรรมขององครักษ์จากผู้อยู่อาศัยชาวยุโรปในแซนซิบาร์ทาวน์[18]
+
+สุลต่านฮาเม็ดสวรรคตอย่างกะทันหันเมื่อเวลา 11:40 EAT (08:40 UTC) ในวันที่ 25 สิงหาคม ค.ศ. 1896[18] พระราชนัดดาวัย 29 พรรษา คาลิด บิน บาร์กาช ซึ่งถูกสงสัยว่ามีส่วนในการลอบปลงพระชนม์[18] ย้ายเข้าประทับในพระราชวังที่แซนซิบาร์ทาวน์โดยปราศจากการอนุมัติจากอังกฤษ ซึ่งเป็นการฝ่าฝืนสนธิสัญญาที่อังกฤษตกลงกับสุลต่านอะลี[18] รัฐบาลอังกฤษนิยมผู้มีคุณสมบัติอีกคนหนึ่ง คือ ฮามัด บิน มุฮามเม็ด ผู้มีใจเอนเอียงต่ออังกฤษมากกว่า กงสุลและเจ้าหน้าที่ทางทูตที่ถูกส่งไปยังแซนซิบาร์ บาซิล เคฟ (Basil Cave) และพลเอกแมตทิวส์ เตือนสุลต่านคาลิดให้ทรงดำริถึงการกระทำของพระองค์อย่างรอบคอบ[23][24] วิธีปฏิบัตินี้เคยประสบความสำเร็จเมื่อสามปีก่อนเมื่อสุลต่านคาลิดทรงพยายามอ้างสิทธิเหนือรัฐสุลต่านหลังสุลต่านอะลีสวรรคต และกงสุลใหญ่อังกฤษ เรนแนลล์ รอดด์ (Rennell Rodd) โน้มน้าวให้พระองค์ทราบถึงภยันตรายของการกระทำนั้น[25]
+
+สุลต่านคาลิดทรงเมินเฉยต่อคำเตือนของเคฟ กองกำลังของพระองค์เริ่มรวมพลที่จัตุรัสพระราชวังภายใต้การบังคับบัญชาของร้อยเอกซาเลห์ (Saleh) องครักษ์พระราชวัง เมื่อสิ้นสุดวัน กองกำลังนี้มีจำนวนถึง 2,800 นาย ติดอาวุธปืนเล็กยาวและปืนคาบศิลา[24] ส่วนใหญ่เป็นพลเรือน แต่กองกำลังนี้มีอัสคารีชาวแซนซิบาร์ที่เข้าข้างสุลต่านคาลิด 700 นาย[24][26] ปืนใหญ่ของสุลต่าน ประกอบด้วย ปืนกลแม็กซิมหลายกระบอก ปืนแก็ตลิง 1 กระบอก ปืนใหญ่วิถีราบสำริดสมัยคริสต์ศตวรรษที่ 17 หนึ่งกระบอก และปืนใหญ่สนามขนาด 12 ปอนด์ 2 กระบอก ทั้งหมดเล็งไปที่เรือรบอังกฤษในท่า[24][26][27] ปืนใหญ่สนามขนาด 12 ปอนด์นี้ สุลต่านได้รับถวายจากสมเด็จพระจักรพรรดิวิลเฮล์มที่ 2 จักรพรรดิเยอรมนี[24] กองกำลังสุลต่านยังครอบครองกองทัพเรือแซนซิบาร์อันประกอบด้วย เรือสลุปไม้หนึ่งลำ เรือหลวงกลาสโกว์ (HHS Glasgow) ซึ่งต่อเป็นเรือยอชท์หลวงของสุลต่านในปี ค.ศ. 1878 โดยมีแบบมาจากเรือฟริเกตของอังกฤษ กลาสโกว์ (Glasgow)[28]
+
+แมตทิวส์และเคฟก็เริ่มรวมพลด้วยเช่นกัน ซึ่งบังคับบัญชาอัสคารีชาวแซนซิบาร์อยู่แล้ว 900 คน ในบังคับบัญชาของร้อยโทอาเทอร์ เอ็ดวาร์ด ฮาริงตัน ไรคีส (Arthur Edward Harington Raikes) แห่งกรมทหารวิลท์ไชร์ (Wiltshire Regiment) ผู้เป็นรองผู้บัญชาการกองทัพแซนซิบาร์และมียศพลจัตวา[24] กะลาสีและนาวิกโยธิน 150 นายขึ้นบกจากเรือลาดตระเวนหุ้มเกราะชั้นเพิร์ล ฟิโลเมล (HMS Philomel) และเรือปืน ทรูช (HMS Thrush) ซึ่งทอดสมออยู่ในท่า[24] กองทัพเรือฉุกเฉินภายใต้การบังคับบัญชาของนาวาเอก โอคาล์เลกแฮน (O'Callaghan) ขึ้นฝั่งในสิบห้านาทีหลังได้รับการร้องขอให้จัดการกับจลาจลใด ๆ ที่เกิดจากประชาชนทั่วไป[24][29] กะลาสีกลุ่มเล็กกว่าภายใต้การบังคับบัญชาของเรือเอก วัตซัน (Watson) แห่งเรือทรูชถูกส่งขึ้นฝั่งเพื่อพิทักษ์สถานกงสุลอังกฤษ ที่ซึ่งพลเมืองอังกฤษถูกขอให้มารวมกันเพื่อการคุ้มครอง[24] เรือหลวงสแพร์โรว์ (HMS Sparrow) เรือปืนอีกลำหนึ่ง แล่นเข้าสู่ท่าเรือและทอดสมอตรงข้ามกับพระราชวังถัดจากเรือทรูช[24]
+
+เกิดความกังวลขึ้นในหมู่นักการทูตอังกฤษเกี่ยวกับความน่าเชื่อถือของทหารอัสคารีของไรคีส แต่พวกเขาพิสูจน์แล้วว่าเป็นทหารที่มั่นคงและเป็นมืออาชีพที่กรำด้วยการฝึกทางทหารและการรบนอกประเทศไปยังแอฟริกาตะวันออกหลายครั้ง ภายหลังทหารอัสคารีเหล่านี้เป็นทหารภาคพื้นดินเพียงกลุ่มเดียวที่ถูกฝ่ายตั้งรับยิงใส่[1] ทหารของไรคีสติดอาวุธปืนแม็กซิมสองกระบอก และปืนใหญ่วิถีราบเก้ากระบอก และประจำอยู่ที่โรงภาษีใกล้ ๆ[30] สุลต่านพยายามให้กงสุลสหรัฐ ริชาร์ด ดอร์ซีย์ โมฮัน (Richard Dorsey Mohun) ยอมรับการขึ้นครองราชย์ของพระองค์ แต่ผู้ส่งสารได้รับแจ้งว่า "เนื่องจากการขึ้นครองราชย์ของพระองค์ยังไม่ถูกรัฐบาลในสมเด็จพระราชินีทวนสอบ จึงเป็นไปไม่ได้ที่จะตอบ"[27]
+
+เคฟส่งสารถึงคาลิดอย่างต่อเนื่อง ขอให้พระองค์ยุติปฏิบัติการของกองทหาร เสด็จออกจากพระราชวัง และกลับบ้าน แต่กลับถูกเพิกเฉย และคาลิดทรงตอบกลับมาว่าพระองค์จะประกาศสถาปนาตนเป็นสุลต่านในเวลา 15.00 น. เคฟแถลงว่า การกระทำเช่นนั้นเป็นการกบฏและการเป็นสุลต่านของคาลิดจะไม่ได้รับการรับรองโดยรัฐบาลอังกฤษ[24] เมื่อเวลา 14.30 น. พระศพสุลต่านฮาเม็ดถูกฝัง หลังจากนั้น 30 นาทีพอดี เสียงยิงสลุตจากปืนในพระราชวังประกาศการสืบราชสันตติวงศ์ของคาลิด เคฟไม่สามารถเปิดฉากสงครามได้หากรัฐบาลไม่อนุมัติ จึงส่งโทรเลขถึงกระทรวงการต่างประเทศของรัฐบาลลอร์ดแห่งซอลสบรีในกรุงลอนดอน ความว่า "เราได้รับอนุญาตให้ยิงพระราชวังจากเรือรบหรือไม่ หากความพยายามทั้งหมดที่จะแก้ปัญหาอย่างสันติไร้ผล"[31] ขณะเดียวกัน เคฟแจ้งกงสุลต่างประเทศอื่นทุกคนว่า ธงทุกผืนจะลดลงครึ่งเสาเพื่อถวายเกียรติแด่สุลต่านฮาเม็ด ธงหนึ่งเดียวที่มิลดครึ่งเสานั้นคือธงสีแดงคันใหญ่ซึ่งปลิวสะบัดที่พระราชวังของคาลิด เคฟยังแจ้งกงสุลด้วยว่า ไม่รับรองคาลิดเป็นสุลต่าน ซึ่งเหล่ากงสุลเห็นด้วย[32]
+
Index: src/test/resources/org/apache/tika/language/zh.test
===================================================================
--- src/test/resources/org/apache/tika/language/zh.test (revision 0)
+++ src/test/resources/org/apache/tika/language/zh.test (revision 0)
@@ -0,0 +1,57 @@
+《E.T.外星人》(英语:E.T. the Extra-Terrestrial)是一部1982年的美国科幻电影,由史蒂文·斯皮尔伯格执导并与凯瑟琳·肯尼迪一起担任制片人,梅丽莎·马西森编剧,亨利·托马斯、迪·沃伦斯、罗伯特·麦克纳夫顿(Robert MacNaughton)、德鲁·巴里摩尔和彼德·考约特主演。讲述了名叫埃利奥特的内向男孩与被困在地球的善良外星人成为朋友的故事。埃利奥特给外星人起名叫“E.T.”(英文“extraterrestrial”的简称,意为外星人),他与自己的哥哥和妹妹联合起来帮助外星人找到回家的路,并且还要避免被母亲及政府发现。
+
+本片的创作理念源于斯皮尔伯格在父母于1960年离婚后想像出来的朋友。1980年,他与马西森会面并在已陷入僵局的科幻恐怖片项目《夜空》(Night Skies)基础上发展出一个新的故事。影片于1981年9月到12月期间在加利福尼亚州进行摄制,拍摄成本为1050万美元。与其他大部分电影不同,本片基本上是按时间顺序拍摄的,这样有利于小演员们给出更具可信度的演出。
+
+影片于1982年6月11日经环球影业发行,是一部成功的大片,票房收入超越《星球大战》,成为当时的历史电影票房总冠军,这个纪录接下来保持了十年之久才于1993年被斯皮尔伯格导演的另一部电影《侏罗纪公园》打破。评论家称赞这是一个永恒的友情故事,烂蕃茄的一项调查也将其评为有史以来最伟大的科幻片。电影于1985年再次上映,后又于2002年为纪念影片诞生20周年重新发行,其中有部分镜头有所改动,还增加了一些内容。
+
+一队外星人在加利福尼亚州的一片树林里搜集植物样本,不久政府特工出现四下搜寻,外星人连忙乘太空船撤离,但其中有一位没能赶上。镜头转至城郊的一户民宅,一个名叫埃利奥特(Elliot)的十岁男孩希望能和自己16岁的哥哥迈克尔(Michael)以及他的朋友们一起玩。他到门口从送货员手中取过比萨饼,回来时发现有什么东西藏在家里的工具棚里。埃利奥特发现那是一只从未见过的生物,被发现时还试图逃离。埃利奥特回到屋里吃饭,告诉家人自己的发现,但没人相信他,于是他用花生酱糖果把外星人从树林中引到了自己的卧室。上床睡觉前,埃利奥特意识到外星人在模仿自己的动作。第二天早上,埃利奥特装病来逃学,留在家里和外星人一起玩,当天下午,迈克尔和5岁大的妹妹格蒂(Gertie)都见到了外星人。三个孩子决定,这事儿可不能让妈妈知道了。他们问起外星人从何而来,外星人用一种神奇的力量将多个球悬浮到空中来代表太阳系,之后又显示出拥有将枯萎植物复活的能力。
+
+次日埃利奥特到学校念书,但他的思想却与外星人保持着联系,例如外星人喝下几罐啤酒时,学校的埃利奥特也醉得东倒西歪,还在生物课上把所有需要解剖的青蛙都放生了。外星人观看电影《蓬门今始为君开》时镜头上出现了约翰·韦恩亲吻玛琳·奥哈拉的情节,埃利奥特也像韦恩那样抓住班上一位女孩并吻了她。
+
+格蒂观看《芝麻街》时会跟着里面的动画人物说话,外星人也学着她说话,然后在埃利奥特的引导下给自己起名叫“E.T.”。E.T.看到漫画书上有人物临时制作了一个通讯设备联系外界求救,于是也决定亲自试试。在埃利奥特的帮助下,他用玩具、雨伞、咖啡罐和一些电子元件制作了一台设备来“打电话回家”。迈克尔发现E.T.的身体健康状况有所恶化,而埃利奥特开始自称“我们”。
+
+万圣节来了,迈克尔和埃利奥特把E.T.打扮成幽灵,让妈妈以为他是格蒂,“三兄妹”一起上街游玩。埃利奥特骑自行车把E.T.带到树林里,后者成功利用那台“通讯仪器”联系了自己的故乡。次日清晨,埃利奥特在林地上苏醒,E.T.却不知所踪,于是他独自回到忧心如焚的家人身边。迈克尔前往树林,在一条水沟旁找到奄奄一息的E.T.,然后带着他去回到埃利奥特身边,埃利奥特也像E.T.一样病重,不知所措的迈克尔只好找来妈妈玛丽(Mary)。玛丽发现次子病重,身边还躺了个怪物后吓坏了,她急匆匆地想要带孩子上医院,这时身穿厚重防护服的政府特工闯了进来,科学家们在她家里安装了医疗设施并把埃利奥特和E.T.分别隔离起来。两者间的联系消失了,E.T.看起来已经死去,之前他复活的一棵植物又干枯了,而埃利奥特则迅速康复。科学家们逐渐离去,只剩伤心欲绝的埃利奥特还陪着一动不动的外星人,一会他突然发现那株干枯的植物又开始复苏了。E.T.复活了,并透露自己的故乡正派太空船来接他。埃利奥特和迈克尔偷了辆面包车,把E.T.带了出去,政府特工、警察在后面穷追不舍,迈克尔的朋友也前来接应,他们换骑上自行车开始四下逃窜,试图引开警察,之后几辆自行车汇聚到了一起,前有堵截后有追兵,眼看走投无路之下,E.T.再次使用了自己的超能力,让所有骑自行车的孩子们都飞到了天上一起朝树林进发。
+
+E.T.和孩子们在树林中降落,E.T.的心脏发出红色的光。玛丽、格蒂和一位政府特工赶到了现场,但他们都没有试图阻止E.T.离去。外星人与迈克尔和格蒂告别,格蒂把对方复活的那盘花送给E.T.做礼物。接下来E.T.又与埃利奥特拥抱,后者伤心地流下了眼泪,E.T.用发光的手指点在埃利奥特的额头上说,“我就在这里”,然后拿起花盆走进太空船。太空船很快起飞了,埃利奥特等人静静地目送它离去,留下了一道彩虹。
+
+ 亨利·托马斯饰埃利奥特,一个十岁大的内向男孩。他渴望能有个好朋友,所以找到意外留在地球上的E.T.后也就与对方成为了朋友,他和外星人之间建立起了心理、生理和情感的纽带。
+ 罗伯特·麦克纳夫顿饰迈克尔,埃利奥特16岁大的哥哥,会打橄榄球,经常取笑弟弟。
+ 德鲁·巴里摩尔饰格蒂,埃利奥特5岁大的淘气妹妹。她一开始被E.T.吓坏了,发出的惊叫也吓坏了E.T.,不过之后很快就喜欢上了这个外星人。
+ 迪·沃伦斯饰玛丽,三个孩子的母亲,不久前与丈夫分居。由于孩子们的隐瞒,她在大部分时间里都对家中来了个外星人一无所知。
+ 彼德·考约特饰片中多次出现的一位政府特工。他的样貌直到影片后半段才出现,但一直没有提及姓名,观众可以从皮带上系的钥匙认出是他。他告诉埃利奥特,自己从10岁那年起就一直等待着想要看到外星人。
+ K.C.马特尔(K. C. Martel)、肖恩·弗莱(Sean Frye)和C·托马斯·豪威尔分别饰演格雷格(Greg)、史蒂夫(Steve)和泰勒(Tyler),都是迈克尔的朋友。他们在影片的高潮戏段帮助埃利奥特和E.T.逃脱政府人员的追捕。
+ 埃丽卡·埃伦尼克(Erika Eleniak)饰演埃利奥特班上被他亲吻的小女孩。
+
+斯皮尔伯格拍摄《第三类接触》时已经和当时年仅5岁的卡里·加菲(Cary Guffey)合作过,所以对和多位孩童演员合作感到很有信心[3]。他面试了数百个男孩来挑选埃利奥特一角的演员[4],之后罗伯特·菲斯克(Robert Fisk)推荐了亨利·托马斯出演[5]。托马斯身穿印第安纳·琼斯的服饰前来参加面试,但在正式试镜时表现欠佳,幸运的是他在即兴表演时引起了导演的注意[3]。为了给出让人信服的流泪表演,他想到了自己死去的狗[6]。罗伯特·麦克纳夫顿为迈克尔一角进行了八次试镜,有时还会和那些参加埃利奥特一角试镜的孩子们一起。德鲁·巴里摩尔告诉斯皮尔伯格自己带领着一支朋克摇滚乐队,给后者留下了深刻印象,觉得她拥有恰到好处的想象力来扮演调皮的小格蒂[5]。斯皮尔伯格喜欢和孩子们合作,他之后表示这段经历让自己感觉已经准备好要成为一名父亲了[7]。
+
+加利福尼亚州马林县一位名叫帕特·威尔士(Pat Welsh)的年长女性居民为E.T.配音,她每天需要吸两包香烟,这样她的嗓音可以达到音效师本·贝尔特(Ben Burtt)希望的理想效果。威尔士一共花了九个半小时来进行录制,然后贝尔特向她支付了380美元的报酬[8]。贝尔特还录制了其他16种声音来制作E.T.的“嗓音”,这其中有人类,也有多种动物。包括斯皮尔伯格、德博拉·温格,还有贝尔特的妻子感冒后睡觉时所发出的声音,以及他南加州大学电影教授发出的打嗝声,动物方面则包括浣熊,海獭,和马[9][10]。
+
+剧组请来南加州大学医疗中心的医生,片中政府特工占领埃利奥特的家后试图对E.T.进行抢救的医生就是由他们扮演的。斯皮尔伯格觉得让演员来说出那些医疗术语很容易失真,所以作出了这样的安排[7]。哈里森·福特诠释了埃利奥特所读学校的校长,埃利奥特在生物课上闯祸后他训斥了孩子的所做所为,还警告对方未成年人饮酒的严重后果,这时埃利奥特的椅子突然升到了空中,把他吓了一大跳,而另一边E.T.正把自己做的“电话”悬浮起来送到楼梯上,格蒂也在一旁帮助。但到了后斯制作时,斯皮尔伯格决定还是把福特的镜头都剪掉了。[5]
+制作
+开发
+
+1960年父母离婚后,斯皮尔伯格通过想象自己有一位外星人的陪伴来填补生活中的空白感。他表示,E.T.就像是“一个我从来都没有过的兄弟和自己不再拥有的父亲那样的朋友”[11]:72。1978年时,他宣布自己打算拍摄一部名为《成长》(Growing Up)的电影,并且用28天拍完。但由于《一九四一》的摄制出现延误,这一项目也暂予搁置,但斯皮尔伯格仍然有打算要拍摄一部有关童年时代的自传电影[8]。他还想过为《第三类接触》拍摄续作,之后又开始按之前计划的那样和约翰·塞尔斯(John Sayles)一起开发一部名为《夜空》的电影,其中讲述一伙邪恶的外星人威胁一户人家的故事[8]。
+
+斯皮尔伯格在突尼西亚拍摄《夺宝奇兵》期间感到很厌倦,童年时代自传电影的创作回忆再度浮现[12]。他将已宣告取消的《夜空》的主要内容告诉了剧作家梅丽莎·马西森,在其基础上发展出了另一段剧情,《夜空》中唯一一位友好的外星人巴迪(Buddy)和一个患有自闭症的孩子成为了朋友。这一剧情的最后一幕是巴迪被抛弃在地球上,正是这一幕激发出了《E.T.外星人》的创作理念[12]。马西森花了8个星期写出了第一稿,标题为《E.T.与我》(E.T. and Me)[12],斯皮尔伯格对之非常满意[5]。马西森接下来又写了两个版本,其中删掉了埃利奥特一个虚伪佞幸的朋友,增加了追逐戏码,斯皮尔伯格还提议加上E.T.醉酒的内容[8]。曾是《夜空》制作商的哥伦比亚电影公司与斯皮尔伯格会面商谈这个剧本,但他们表示对这么“一部懦弱的华特迪士尼电影”不感兴趣,于是斯皮尔伯格联系了对此更能接受的希德·欣伯格(Sid Sheinberg),后者是MCA公司的总裁[13]。
+
+艾德·维罗(Ed Verreaux)为E.T.制作了一个耗资70万美元的原型,但斯皮尔伯格觉得这个原型毫无用处[8]。之前为《第三类接触》设计了外星人的卡罗·兰博蒂(Carlo Rambaldi)获聘设计E.T.的电子动画。他从自己的画作《三角洲的女人》(Women of Delta)中获得灵感,给外星人创作了一个独特的,可以伸展的脖子[5]。外星人的面部设计灵感来自卡尔·桑德堡、阿尔伯特·爱因斯坦和欧内斯特·海明威的脸[14]。制片人凯瑟琳·肯尼迪造访了朱尔斯·斯坦眼科研究所对真实的和玻璃制眼球进行研究。她聘请了研究所的工作人员给E.T.创造眼睛,因为她认为眼睛在与观众交流的过程中至关重要[3]。为了便于拍摄,工作人员一共制作了四颗E.T.的头,其中一个主要用于电子动画,另外三个则拥有不同的面部表情,并配有服装[14]。身材矮小的塔玛拉·德·特罗克斯(Tamara De Treaux)和帕特·比隆(Pat Bilon)[8],以及12岁大,天生就没有双腿的马修·德梅里特(Matthew DeMeritt)[15]根据需要拍摄的不同镜头来轮流穿上服装。德梅里特实际上是用自己的手来行走,出演了所有E.T.笨拙走动或摔倒的镜头。E.T.的头放在演员的头部上门,演员则可以通过木偶胸前的开衩看到前方[5]。专业默剧演员卡普里斯·罗斯(Caprice Roth)充当假肢扮为E.T.的双手[3]。E.T.的木偶模型花了三个月进行制作,耗资150万美元[16]。斯皮尔伯格宣称,这是一个丑陋到“只有(它的)妈妈才会爱(它)的东西”[5]。瑪氏食品因为觉得E.T.实在太难看而拒绝片中使用他们所生产的M&M's巧克力,认为这么一个怪物会吓坏孩子们。好时于是抓住机会向剧组提供其生产的花生酱糖果[17]。片中E.T.的通讯设备则是由科学和技术教育工作者亨利·范伯格(Henry Feinberg)制作[18][19]。
+拍摄
+
+《E.T.外星人》于1981年9月开始拍摄[20],使用的项目代号为《一个男孩的生活》(A Boy's Life),因为斯皮尔伯格不希望有任何人发现或剽窃其剧情。众演员只能在大门紧锁的屋里看剧本,片场的所有人都需要佩戴身份证件[3]。剧组首先在卡尔弗城一所高中拍摄了两天,之后的11天又分别在洛杉矶的北岭(Northridge)和图洪加(Tujunga)继续[8]。这以后剧组花了42天时间在卡尔弗城的莱尔德国际影城(Laird International Studios)拍摄埃利奥特家中的内景镜头。之后的6天时间里,剧组又来到克雷森特城附近一片红木森林进行拍摄[8][12]。斯皮尔伯格基本上是按照片中的时间顺序进行拍摄,这样有利于小演员们给出更具可信度的演出。拍摄迈克尔首次见到外星人的镜头时,麦克纳夫顿吓了一大跳,他向后一跳,撞倒了身后的货架。按时间顺序拍摄让小演员们与E.T.建立起了情感的纽带,使得接近片尾的医院桥段更加感人[7]。斯皮尔伯格还确保木偶模型不会出现在片场,保持一种外星人可能是真的的映象。他还首次没有对影片大部分内容进行分镜,希望能让表演更即兴,更真实[20]。影片前半截除迪·沃伦斯外,没有任何一个成年人的上半身在镜头上出现过,这一做法是在向特克斯·艾弗里(Tex Avery)的动画作品致敬[5]。所有镜头一共花了61天时间拍完,比原计划要快4天[12]。据斯皮尔伯格所说,片中E.T.藏在埃利奥特的衣柜里并假装成一个玩具布偶这一情节来自罗伯特·泽米基斯,后者看过导演寄给他的剧本后给出了这一建议[21]。
+
+已经多次和斯皮尔伯格合作过的作曲家约翰·威廉姆斯谱写了本片的配乐,他形容,要创作音乐来让人对一个看起来这么古怪的生物产生同情的确是一次挑战。就像之前两人合作时一样,斯皮尔伯格对威廉姆斯创作的每一段主题都感到满意,并且会将之用到电影中,他对片尾追逐戏的配乐是如此钟爱,以至于亲自对这场戏进行剪辑,让镜头与音乐合拍。[22]威廉姆斯使用了现代派乐风,特别采用了多调性,同时演奏两个不同调性的音乐。利底亚模式(Lydian mode)也可以在多调性方式中使用。作曲家将多调性和利底亚模式结合,表达出一种神秘、梦幻般的英雄主义风格。他创作的主题中注重使用竖琴、钢琴、钢片琴与其他键盘乐器和打击乐器,表现出E.T.孩子般的天性和机械、笨拙的一面。
+
+抄袭指控
+
+有报道称本片抄袭了1967年的剧本《异形》(The Alien),该剧本由印度籍孟加拉导演萨蒂亚吉特·雷伊创作。雷伊声称,如果没有他创作的《异形》剧本,《E.T.外星人》根本就不可能存在。斯皮尔伯格否认这其中存在抄袭,表示当雷伊的剧本在好莱坞流通时自己还在念高中[24]。《明星周末杂志》(Star Weekend Magazine)驳斥了斯皮尔伯格的说法,指出他1965年时就已高中毕业,1969年时已经开始在好莱坞从事导演工作[25]。除《E.T.外星人》以外,还有人认为斯皮尔伯格之前的作品《第三类接触》也是受到《异形》的启发[26][27]。
+
+此外,资深电影人马丁·西科塞斯和理查德·阿滕伯勒同样认为斯皮尔伯格受到了雷伊剧本的影响[28]。
+
+斯皮尔伯格是因父母离婚而构想了《E.T.外星人》的故事[30]。《华盛顿邮报》的加里·阿诺德(Gary Arnold)认为影片“从本质上是一种精神性的自传”,描述了电影人作为典型郊区孩子所拥有的非典型的神秘而热切的想象[31]。片中埃利奥特通过把温度计贴在电灯泡上,以及用电热毯盖住自己的头部来佯装生病,斯皮尔伯格儿时经常使用这样的把戏[11]:13。迈克尔对埃利奥特的戏弄呼应着斯皮尔伯格对小妹妹的捉弄[5],迈克尔从一开始经常玩弄弟弟的坏哥哥演变成保护他的好兄长也折射出斯皮尔伯格在失去父亲后开始照顾妹妹的经历[7]。
+
+评论家关注埃利奥特和E.T.境遇的相似之处,埃利奥特被父亲抛弃,E.T.则被同胞遗留在地球上[32][33]。《纽约时报》的A·O·斯科特(A.O. Scott)在文章中写道,虽然E.T.“更明显是个绝望的弃儿”,但埃利奥特也以自己的方式遭受着渴望家庭的折磨[34]。E.T.也正好是由埃利奥特(Elliott)名字的第一和最后一个字母组成[35]。成长是电影的核心主题,评论家亨利·希恩(Henry Sheehan)形容本片是从一个迷失男孩(埃利奥特)的视角重新讲述了彼得潘的故事:没有埃利奥特的帮助,E.T.无法在地球上生存,就像彼得潘在情感上无法在梦幻岛生存下去一样,政府部门的科学家就像是梦幻岛上的海盗[36]。《纽约时报》的文森特·坎比(Vincent Canby)也有类似的看法,称片中“来自……《小飞侠》和《绿野仙踪》的元素随处可见”[37]:53。一些评论家认为斯皮尔伯格对郊区的描写非常黑暗,与人们的普遍看法相反。据A·O·斯科特表示,“郊区中无人看管的儿童和郁郁寡欢的家长,破损的玩具和名牌垃圾食品,这听起来更像是瑞蒙·卡佛的故事”[34]。沙龙网站(Salon.com)的查尔斯·泰勒(Charles Taylor)写道:“斯皮尔伯格的电影虽然经常被视为对好莱坞理想化家庭和郊区的反映,但实际上并非如此。这些家庭都背负着文化批评家卡罗尔·安·马林(Karal Ann Marling)所说的那种‘苦心经营的标志’”[30]。
+
+还有些影评人在E.T.和耶稣之间找到了宗教性的联系[38][39]。安德鲁·奈吉尔斯(Andrew Nigels)形容E.T.的故事就是先因“军事科学而受难”,再“由爱和信仰复活”[40]。科幻小说作家和评论家亚当·罗伯茨则称这部电影是世俗化的类宗教神话,认为整个剧情是对《新约》中“凡要承受神国的,若不想小孩子,断不能进去”的重新阐释,电影情节更是多次与基督的生命经历相和[41]。据斯皮尔伯格的传记作者约瑟夫·麦克布莱德(Joseph McBride)表示,环球影业设计的海报让人想到米开朗基罗的《创造亚当》,上面的商标则写着“Peace”(意为“和平”),希望能够吸引更多的基督徒观看影片[12]。斯皮尔伯格则表示,自己无意让电影变成宗教寓言,他开玩笑说:“要是我去和我妈说,‘妈,我想拍部基督教寓言式的电影。’你猜她会怎么说?她在洛杉矶经营过一家犹太餐馆”[29]。
+
+许多作家也试图通过其它角度对本片加以分析,有观点将影片解读为现代童话[42],也有人将其视为心理分析的方式[33][42]。制片人凯瑟琳·肯尼迪指出,宽容是《E.T.外星人》的重要主题,之后斯皮尔伯格的多部电影,如《辛德勒的名单》都将以此为核心[5]。少年时就经常独来独往的斯皮尔伯格觉得本片是“一个少数人的故事”[37]:22,他觉得片中通讯的主题与相互了解的愿望相辅相成,人类与外星人的友谊就像是现代生活中的敌人可以如何学会克服各自分歧的一个比喻[43]。
+