# Changes since [3.3.0](./3.3.0.md)

- Require Python 3.7 or 3.8, drop support for Python 3.4, 3.5 and 3.6

- Fix / rewrite `setup.py`

  - Fix `python3 setup.py sdist bdist_wheel`, and pypi package
    - Had to move `ui/` directory into `pyglossary/`
  - Switch from `distutils` to `setuptools`
  - Remove `py2exe`

- Add interactive command line user interface

  - Automatically selected if input & output file arguments are not passed **and** one of these:
    - On Linux and no `$DISPLAY` is not set
    - On Mac and no `tkinter` module is found
    - `--ui=cmd` flag is passed

- New format support:

  - Add read support for FreeDict, [#206](https://github.com/ilius/pyglossary/issues/206)
  - Add read support for Zim (Kiwix)
  - Add read and write support for Kobo E-Reader Dictfile (.df)
  - Add write support for DICT.org `dictfmt` source file
  - Add read support for [dictunformat](https://linux.die.net/man/1/dictunformat) output file
  - Add write support for JSON
  - Add read support for Dict.cc (SQLite3)
  - Add read support for [JMDict](https://www.edrdg.org/jmdict/j_jmdict.html), [#239](https://github.com/ilius/pyglossary/issues/239)
  - Add basic read support for Wiktionary Dump (.xml)
  - Add read support for [cc-kedict](https://github.com/mhagiwara/cc-kedict)
  - Add read support for [DigitalNK](https://github.com/digitalprk/dicrs) (SQLite3)
  - Add read support for [Wordset.org](https://github.com/wordset/wordset-dictionary) JSON directory

- Remove Omnidic write support (Unmaintained J2ME dictionary)

- Remove Octopus MDict Source plugin

- Remove Babylon Source plugin

- BGL Weader: improvements

- DictionaryForMIDs Writer: fix non-working code

- Gettext Source (po) Writer: fix info header

- MOBI E-Book Writer: fix sort order, fix and test kindlegen codes, add `kindlegen_path` option, [#112](https://github.com/ilius/pyglossary/issues/112)

- EPUB-2 E-Book Writer: fix sort order

- XDXF Reader: rewrite with `etree.iterparse` to avoid using too much RAM

- Lingoes Source (LDF) Reader: fix ignoring info/metadata header

- dict_org.py: rewrite broken plugin (Reader and Writer)

- DSL Reader: fix losing metadata/info

- Aard 2 (slob) Reader:

  - Fix adding css/js files as normal entries
  - Add `bword://` prefix to entry links
  - Fix duplicate entries issue by keeping a set of blob IDs, [#224](https://github.com/ilius/pyglossary/issues/224)
  - Detect and pass defiFormat

- Aard 2 (slob) Writer:

  - Fix content_type detection
  - Remove `bword://` prefix from entry links
  - Add resource files / data entries, [#243](https://github.com/ilius/pyglossary/issues/243)
  - Fix replacing image paths
  - Show log events from `slob.py` in debug mode
  - Change default `compression` to `zlib`
  - Allow passing empty `compression`

- Octopus MDict Reader:

  - Read MDX file twice to load links
  - Count data entries as part of `len(reader)` for progressbar

- StarDict Writer:

  - Copy "copyright" and "publisher" values to "description"
  - Add source and target language codes to the end of bookname
  - Add write-option `stardict_client: bool`
    Set `True` to make glossary more compatible with StarDict 3.x
  - Fix broken result when `sametypesequence` option is given and a definitions contains `|`
  - Allow `sametypesequence=x` for xdxf
  - Add `merge_syns` option
  - Allow `sametypesequence=None` option

- XDXF Reader:

  - Fix/improve xdxf to html transformation

- Kobo Writer:

  - Fix get_prefix algorithm and sorting order, with tests, [#219](https://github.com/ilius/pyglossary/issues/219)
  - Replace `<img src=...` tags with `[Image: name.bmp]`, [#219](https://github.com/ilius/pyglossary/issues/219)
    - and show a warning about data entries
  - Additional keywords as alternatives, [#232](https://github.com/ilius/pyglossary/issues/232)
  - Fix support for alternates: duplicate entries based on word prefix, [#238](https://github.com/ilius/pyglossary/issues/238)
  - Show headword in title of alternate entries, [#238](https://github.com/ilius/pyglossary/issues/238), [#245](https://github.com/ilius/pyglossary/issues/245)
  - Strip full html definition, [#246](https://github.com/ilius/pyglossary/issues/246)

- CSV:

  - Add `delimiter` option to Reader and Writer
  - Read and write info
  - Writer: accept bool option `add_defi_format=True` (default False)

- AppleDict Writer:

  - AppleDict Writer: replace fix_sound_link() code with a single line
  - AppleDict Writer should not call glos.setDefaultDefiFormat

- MDX Reader:

  - Replace `entry://` with `bword://` in MDX Reader instead of AppleDict Writer
  - Fix internal `href="x:"` and `href="d:"` links
  - Fix `file://` in images path, fix [#243](https://github.com/ilius/pyglossary/issues/243)

- User Interface improvements and fixes:

  - ui_gtk: add About tab and more improvements
  - ui_tk: replace About dialog with About tab and more improvements
  - ui_cmd: improvements in progressbar
  - ui_cmd: allow "=" in value of read/write options

- Add a list of 208 languages and ~40 writing systems

  - Detect `sourceLang` and `targetLang` from glossary name/title
  - Auto-select between `<b>` and `<big>` tags depending on writing system
    - Using `glos.titleElement` method, used in FreeDict, JMDict and Dict.cc writers
  - `glos.sourceLang` and `glos.targetLang` properties (with setters) as `Lang` objects
  - `glos.sourceLangName` and `glos.targetLangName` properties (with setters) as `str`
    - Used in several plugins

- Break compatibility of plugins

  - Drop support for read and write functions (outside a class)
  - Now we only support Reader class and Writer class
  - Reader class must have these methods
    - `__init__(self, glos)`
    - `open(self, filename)`
      - Here glossary info must be read from file and set with `glos.setInfo`
    - `__len__(self) -> int`
      - Should return the number or entries, or zero if it's too costly
    - `__iter__(self) -> "Iterator[BaseEntry]"`
      - Can be a generator
    - `close(self)`
  - Writer class must have these methods
    - `__init__(self, glos)`

    - `open(self, filename)`

      - Here glossary info must be read from `glos.getInfo` or `glos.iterInfo` and written to file

    - `write(self) -> "Generator[None, BaseEntry, None]"`

      - Entries must be fetched with `entry = yield` in a `while True` loop:

        ```python
        while True:
        	entry = yield
        	if entry is None:
        		break
        	# process and write entry into file(s)
        ```

    - `finish(self)`
  - Read options and write options must be set to their default values as class attributes
    - See `pyglossary/plugins/csv_pyg.py` plugin for example
  - `sortKey` must be an instance method of Writer, instead of a function outside any class
    - Only for plugins that need sorting before write

- Refactor and cleanup `Glossary` class

  - Removed or replaced most of class/static attributes of `Glossary`
    - To see the diff, run `git diff [3.3.0](./3.3.0.md)..master -- pyglossary/glossary.py`
  - Removed `glos.addEntry` method
    - If you use it in your program, replace with `glos.addEntryObj(glos.newEntry(word, defi, defiFormat))`
  - Removed instance methods:
    - `getMostUsedDefiFormats`
    - `iterEntryBuckets`
    - `zipOutDir` and `archiveOutDir`
      - Moved to `pyglossary/glossary_utils.py`
      - `archiveOutDir` renamed to `compressOutDir`
    - `writeDict`
    - `iterSqlLines` -> moved to `pyglossary/plugins/sql.py`
    - `reverse`, `takeOutputWords`, `searchWordInDef` -> moved to `pyglossary/reverse.py`
  - Values of `Glossary.plugins` is changed to `plugin_prop.PluginProp` instances
  - Change `glos.writeTxt` arguments
    - Replace `sep1` and `sep2` with `entryFmt`
    - Replace `rplList` with `defiEscapeFunc`, `wordEscapeFunc` and `tail`
    - Remove `iterEntries`, `entryFilterFunc`
    - Method returns `Generator[None, BaseEntry, None]` instead of `bool`
    - See for usage example:
      - `pyglossary/glossary.py` -> `def writeTabfile`
      - `pyglossary/plugins/dict_org_source.py`
      - `pyglossary/plugins/json_plugin.py`
      - `pyglossary/plugins/lingoes_ldf.py`
      - `pyglossary/plugins/sdict_source.py`

- Refactor, cleanup and fixes in `Entry` and `DataEntry` classes

  - Replace `entry.getWord()` with `entry.word`
  - Replace `entry.getWords()` with `entry.l_word`
  - Replace `entry.getDefi()` with `entry.defi`
  - Remove `entry.getDefis()`
    - Drop handling alternate definitions in `Entry` objects
  - Replace `entry.getDefiFormat()` with `entry.defiFormat`
  - Add `entry.b_word` and `entry.b_defi` shortcuts that give `bytes` (UTF-8)
  - Replace `dataEntry.getData()` with `dataEntry.data`
  - Add `__slots__` to Entry and DataEntry classes
  - Fix `DataEntry` in indirect mode
    - Mistaken for Entry with defi=DATA, and file content discarded
    - Save resource files in user's cache directory when loading input glossary into memory
      - Move file to output glossary on `dataEntry.save(...)`
  - Fix `Entry.getRawEntrySortKey` not being alternates-aware, broke StarDict Writer
  - `DataEntry`: save: use `shutil.copy` if has `_tmpPath`, and set `_tmpPath`

- New features of `Entry`

  - `entry.stripFullHtml()`, remove `<html... <head>...</head>...<body>`
    - Used in Kobo and Kobo Dictfile writers
    - Add tests

- Fix `glos.writeTabfile`:

  - Remove `\r` from definitions and info values
  - Fix not escaping word

- Fix/improve html detection in definitions

- Switch to lazy imports of non-standard modules in plugins

- Optimize RAM usage of indirect conversion

  - To write StarDict, EPUB and DictionaryForMIDs glossaries, we need to load all entries into RAM to sort them

- Other new features of Glossary class

  - `glos.getAuthor()` to get "author", or "publisher" (as fallback)
  - `glos.removeHtmlTagsAll()` method, can be called by plugins' writer
  - `glos.collectDefiFormat(maxCount)` extract defiFormat counts
    - by reading first `maxCount` entries. (then iterator will be reset)
    - Used in StarDict Writer
  - Show memory usage in trace mode

- Bug fixes and improvements in code base

  - Apply entry filter when iterating over reader, fix [#251](https://github.com/ilius/pyglossary/issues/251)

    - Fixes wrong sort order for some glossaries (converting to StarDict or other formats that need sort)

  - Fixes and improvements in `TextGlossaryReader` class

    - Fix ignoring glossary defaultDefiFormat

  - Fix evaluating `None` value in read/write options

- Support reading multi-file Tabfile or other text formats

  - Example: `file.txt`, `file.txt.1`, `file.txt.2`
  - Need to add `file_count` info key, for example: `##file_count	3`

- Fixes in Tabfile Writer

  - Fix not escaping ""

- Add/update documentation

  - Update README.md
  - Add Termux guides in `doc/termux.md`
  - Move AppleDict guides to `doc/apple.md`
  - Move LZO notes to `doc/lzo.md`
  - Minify and compress `.svg` files in `doc/` folder

- Switch to f-strings, pep8 fixes, add types, style changes and refactoring

- New command line flags:

  - `--log-time` to show datetime in logs (override `log_time` in config.json)
  - `--no-alts` to disable alternates handling
  - `--normalize-html` to lowercase tags (for now)
  - `--cleanup` and `--no-cleanup`
  - `--info` to save `.info` file alongside output file
