class TatoebaSentenceSource extends SentenceSource {

  private final List<TatoebaSentence> sentences;
  private final Scanner scanner;

  // Each sentence is one article, but count anyway so it's coherent with what the Wikipedia code does:
  private int articleCount = 0;
  
  TatoebaSentenceSource(InputStream textInput, Language language) {
    this(textInput, language, null);
  }

  /** @since 3.0 */
  TatoebaSentenceSource(InputStream textInput, Language language, Pattern filter) {
    super(language, filter);
    scanner = new Scanner(textInput);
    sentences = new ArrayList<>();
  }

  @Override
  public boolean hasNext() {
    fillSentences();
    return sentences.size() > 0;
  }

  @Override
  public Sentence next() {
    fillSentences();
    if (sentences.isEmpty()) {
      throw new NoSuchElementException();
    }
    TatoebaSentence sentence = sentences.remove(0);
    String title = "Tatoeba-" + sentence.id;
    return new Sentence(sentence.sentence, getSource(), title, "http://tatoeba.org", ++articleCount);
  }

  @Override
  public String getSource() {
    return "tatoeba";
  }

  private void fillSentences() {<FILL_FUNCTION_BODY>}

  private static class TatoebaSentence {
    long id;
    String sentence;
    private TatoebaSentence(long id, String sentence) {
      this.id = id;
      this.sentence = Objects.requireNonNull(sentence);
    }
  }
}

    while (sentences.isEmpty() && scanner.hasNextLine()) {
      String line = scanner.nextLine();
      if (line.isEmpty()) {
        continue;
      }
      String[] parts = line.split("\t");
      if (parts.length != 3) {
        System.err.println("Unexpected line format: expected three tab-separated columns: '" + line  + "', skipping");
        continue;
      }
      long id = Long.parseLong(parts[0]);
      String sentence = parts[2];  // actually it's sometimes two (short) sentences, but anyway...
      if (acceptSentence(sentence)) {
        sentences.add(new TatoebaSentence(id, sentence));
      }
    }
  
<methods>public abstract java.lang.String getSource() ,public abstract boolean hasNext() ,public abstract org.languagetool.dev.dumpcheck.Sentence next() ,public void remove() ,public java.lang.String toString() <variables>static final int MAX_SENTENCE_LENGTH,static final int MIN_SENTENCE_LENGTH,static final int MIN_SENTENCE_TOKEN_COUNT,private final non-sealed java.util.regex.Pattern acceptPattern,private int ignoreCount,private final non-sealed org.languagetool.tokenizers.Tokenizer wordTokenizer