/* LanguageTool, a natural language style checker
* Copyright (C) 2007 Daniel Naber (http://www.danielnaber.de)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package org.languagetool.language;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import org.jetbrains.annotations.NotNull;
import org.languagetool.Language;
import org.languagetool.LanguageMaintainedState;
import org.languagetool.chunking.Chunker;
import org.languagetool.chunking.GermanChunker;
import org.languagetool.languagemodel.LanguageModel;
import org.languagetool.languagemodel.LuceneLanguageModel;
import org.languagetool.rules.*;
import org.languagetool.rules.de.*;
import org.languagetool.rules.de.SentenceWhitespaceRule;
import org.languagetool.synthesis.GermanSynthesizer;
import org.languagetool.synthesis.Synthesizer;
import org.languagetool.tagging.Tagger;
import org.languagetool.tagging.de.GermanTagger;
import org.languagetool.tagging.disambiguation.Disambiguator;
import org.languagetool.tagging.disambiguation.rules.de.GermanRuleDisambiguator;
import org.languagetool.tokenizers.CompoundWordTokenizer;
import org.languagetool.tokenizers.SRXSentenceTokenizer;
import org.languagetool.tokenizers.SentenceTokenizer;
import org.languagetool.tokenizers.de.GermanCompoundTokenizer;
/**
* Support for German - use the sub classes {@link GermanyGerman}, {@link SwissGerman}, or {@link AustrianGerman}
* if you need spell checking.
*/
public class German extends Language implements AutoCloseable {
private static final Language GERMANY_GERMAN = new GermanyGerman();
private Tagger tagger;
private Synthesizer synthesizer;
private SentenceTokenizer sentenceTokenizer;
private Disambiguator disambiguator;
private GermanChunker chunker;
private CompoundWordTokenizer compoundTokenizer;
private GermanCompoundTokenizer strictCompoundTokenizer;
private LanguageModel languageModel;
/**
* @deprecated use {@link GermanyGerman}, {@link AustrianGerman}, or {@link SwissGerman} instead -
* they have rules for spell checking, this class doesn't (deprecated since 3.2)
*/
@Deprecated
public German() {
}
@Override
public Language getDefaultLanguageVariant() {
return GERMANY_GERMAN;
}
@Override
public Disambiguator getDisambiguator() {
if (disambiguator == null) {
disambiguator = new GermanRuleDisambiguator();
}
return disambiguator;
}
/**
* @since 2.9
*/
@Override
public Chunker getPostDisambiguationChunker() {
if (chunker == null) {
chunker = new GermanChunker();
}
return chunker;
}
@Override
public String getName() {
return "German";
}
@Override
public String getShortCode() {
return "de";
}
@Override
public String[] getCountries() {
return new String[]{"LU", "LI", "BE"};
}
@Override
public Tagger getTagger() {
Tagger t = tagger;
if (t == null) {
synchronized (this) {
t = tagger;
if (t == null) {
tagger = t = new GermanTagger();
}
}
}
return t;
}
@Override
@NotNull
public Synthesizer getSynthesizer() {
if (synthesizer == null) {
synthesizer = new GermanSynthesizer();
}
return synthesizer;
}
@Override
public SentenceTokenizer getSentenceTokenizer() {
if (sentenceTokenizer == null) {
sentenceTokenizer = new SRXSentenceTokenizer(this);
}
return sentenceTokenizer;
}
@Override
public Contributor[] getMaintainers() {
return new Contributor[] {
new Contributor("Jan Schreiber"),
Contributors.DANIEL_NABER,
};
}
@Override
public List<Rule> getRelevantRules(ResourceBundle messages) throws IOException {
return Arrays.asList(
new CommaWhitespaceRule(messages,
Example.wrong("Die Partei<marker> ,</marker> die die letzte Wahl gewann."),
Example.fixed("Die Partei<marker>,</marker> die die letzte Wahl gewann.")),
new GenericUnpairedBracketsRule(messages,
Arrays.asList("[", "(", "{", "„", "»", "«"),
Arrays.asList("]", ")", "}", "“", "«", "»")),
new UppercaseSentenceStartRule(messages, this,
Example.wrong("Das Haus ist alt. <marker>es</marker> wurde 1950 gebaut."),
Example.fixed("Das Haus ist alt. <marker>Es</marker> wurde 1950 gebaut.")),
new MultipleWhitespaceRule(messages, this),
// specific to German:
new OldSpellingRule(messages),
new SentenceWhitespaceRule(messages),
new GermanDoublePunctuationRule(messages),
new MissingVerbRule(messages, this),
new GermanWordRepeatRule(messages, this),
new GermanWordRepeatBeginningRule(messages, this),
new GermanWrongWordInContextRule(messages),
new AgreementRule(messages, this),
new CaseRule(messages, this),
new CompoundRule(messages),
new DashRule(messages),
new VerbAgreementRule(messages, this),
new SubjectVerbAgreementRule(messages, this),
new WordCoherencyRule(messages),
new SimilarNameRule(messages),
new WiederVsWiderRule(messages)
);
}
/**
* @since 2.7
*/
public CompoundWordTokenizer getNonStrictCompoundSplitter() {
if (compoundTokenizer == null) {
try {
GermanCompoundTokenizer tokenizer = new GermanCompoundTokenizer(false); // there's a spelling mistake in (at least) one part, so strict mode wouldn't split the word
compoundTokenizer = word -> new ArrayList<>(tokenizer.tokenize(word));
} catch (IOException e) {
throw new RuntimeException("Could not set up German compound splitter", e);
}
}
return compoundTokenizer;
}
/**
* @since 2.7
*/
public GermanCompoundTokenizer getStrictCompoundTokenizer() {
if (strictCompoundTokenizer == null) {
try {
strictCompoundTokenizer = new GermanCompoundTokenizer();
} catch (IOException e) {
throw new RuntimeException("Could not set up strict German compound splitter", e);
}
}
return strictCompoundTokenizer;
}
@Override
public synchronized LanguageModel getLanguageModel(File indexDir) throws IOException {
if (languageModel == null) {
languageModel = new LuceneLanguageModel(new File(indexDir, getShortCode()));
// for testing:
//languageModel = new BerkeleyRawLanguageModel(new File("/media/Data/berkeleylm/google_books_binaries/ger.blm.gz"));
//languageModel = new BerkeleyLanguageModel(new File("/media/Data/berkeleylm/google_books_binaries/ger.blm.gz"));
}
return languageModel;
}
/** @since 3.1 */
@Override
public List<Rule> getRelevantLanguageModelRules(ResourceBundle messages, LanguageModel languageModel) throws IOException {
return Arrays.<Rule>asList(
new GermanConfusionProbabilityRule(messages, languageModel, this)
);
}
/**
* Closes the language model, if any.
* @since 3.1
*/
@Override
public void close() throws Exception {
if (languageModel != null) {
languageModel.close();
}
}
@Override
public LanguageMaintainedState getMaintainedState() {
return LanguageMaintainedState.ActivelyMaintained;
}
@Override
public int getPriorityForId(String id) {
switch (id) {
case "KOMMA_ZWISCHEN_HAUPT_UND_NEBENSATZ": return -10;
case "OLD_SPELLING_INTERNAL": return 10;
}
return 0;
}
}