document and optimise the dictionary build process a bit
authorRaphaël Jakse <raphael.trivabble@jakse.fr>
Sat, 29 Aug 2020 08:54:52 +0000 (10:54 +0200)
committerRaphaël Jakse <raphael.trivabble@jakse.fr>
Sat, 29 Aug 2020 08:54:52 +0000 (10:54 +0200)
README.md
dict-dists-extractor/Makefile
l10n/po/fr/trivabble.po
public/config.js.sample
public/index.html
public/trivabble.js

index 51253d5e08537e2e88320bf05363ece7bbf297e8..8e898ed5667286fc5833ade067d49b3e162e1a9f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -157,3 +157,16 @@ A full example is available in (doc/trivabble-apache-host.conf.sample)[doc/triva
 
 :warning: Be careful to allow enough concurrent processes / threads / workers on your web server.
 Each player requires one long-standing connection (XHR, SSE or WebSocket), plus small requests when not using WebSockets.
+
+## Enable the spell checker
+
+This is an experimental feature. The process of building the dictionaries takes a lot of disk space.
+
+Install `aspell` (to have the `word-list-compress` command) and run:
+
+```sh
+cd dict-dists-extractor
+make
+```
+
+Then, set `ENABLE_CHECK_SPELLING` to `true` in `public/config.js`.
index b83322d851b61dbf327d4a2d5f6dee324df76853..938ffbbdbeb721b7af31c7ebe01352818824a31c 100644 (file)
@@ -1,8 +1,7 @@
 # -*- Makefile -*-
 
 ROOT_DICT = ../public/dict
-#OBJ_DIR = .
-OBJ_DIR = /tmp/trivabble
+OBJ_DIR = obj
 
 # 0MB < dictionary size < 10MB
 SMALL = br ca cy da de en es fr ga hr hy is lv nl no pt sv
@@ -12,6 +11,10 @@ LARGE = bg el eo it pl ro ru sk sl uk
 VERY_LARGE = ar cs et fi
 LANGS = $(SMALL) $(LARGE)
 
+
+DICT_RULE_PRELUDE = sortuniq() { cat > "$$1"; sort -u -o "$$1" "$$1"; }; \
+echo Building $@ from $<
+
 # he and hu: can not be generated
 # af eu la ms tr xk: no aspell dictionary
 
@@ -22,7 +25,9 @@ LOWS = $(addsuffix .low,$(LANGS))
 DICTS = $(addsuffix .dict,$(LANGS))
 
 DEPEND = Makefile
-MAKEFLAGS = -s
+#MAKEFLAGS = -s
+
+.PHONY: all required count clean low
 
 all: required
        make $(addprefix check-,$(LANGS))
@@ -38,40 +43,38 @@ count:
 
 low: $(LOWS)
 
-required: $(OBJ_DIR) $(OBJ_DIR)/src.mk $(ROOT_DICT)
+required: ${OBJ_DIR} ${OBJ_DIR}/src.mk ${ROOT_DICT}
 
 $(OBJ_DIR)/src.mk:
        echo Creation language table
        wget $(ASPDICT) -q -O - | \
        awk 'BEGIN { base="'`dirname $(ASPDICT)`'" } \
          /<tr><td><a/ { $$0 = gensub(/.*"(.+)".*"(.+)\/(.+)".*/, "\\1 \\2 \\3", "g"); \
-                        printf "$(OBJ_DIR)/%s.dir: $(OBJ_DIR)/%s\n\n", $$1, $$3; \
-                            printf "$(OBJ_DIR)/%s:\n", $$3; \
+                        printf "${OBJ_DIR}/%s.dir: $(OBJ_DIR)/%s\n\n", $$1, $$3; \
+                            printf "${OBJ_DIR}/%s:\n", $$3; \
                                         printf "\techo Downloading %s dictionary source\n", $$1; \
                                         printf "\twget -q %s/%s/%s -O $$@\n\n", base, $$2, $$3 } \
          /<\/table>/ { exit }' > $@
 
-include $(wildcard $(OBJ_DIR)/src.mk)
-
-INSTALL_ASPELL_DICT = cd $(OBJ_DIR) && \
-    tar xjf $(1) && \
-    cd $(2) && \
-       ./configure && \
-       make
-
-ASPELL_DUMP_MASTER = aspell --dict-dir=$(2) -d $(1) dump master $(1) | \
-    aspell --dict-dir=$(2) -l $(1) expand | \
-    tr -s '[:space:]' '\n' | \
-    LC_ALL=C sort -S28G -u > $(3)
+include $(wildcard ${OBJ_DIR}/src.mk)
 
 %.dir:
        echo Installing $@ dictionary
-       $(call INSTALL_ASPELL_DICT,$<,$(<:.tar.bz2=))
-       mv $(<:.tar.bz2=) $@
+       cd "$$(dirname "$@")" && \
+       tar -xjf "$$(basename "$<")" && \
+       cd "$$(basename "$(<:.tar.bz2=)")" && \
+       ./configure && \
+       make && \
+        cd .. && \
+       mv "$$(basename "$<" .tar.bz2)" "$$(basename "$@")"
 
 %.low: %.dir
-       echo Building list of word $@
-       $(call ASPELL_DUMP_MASTER,$(patsubst $(OBJ_DIR)/%.dir,%,$<),$<,$@)
+       @echo "Building list of word $@"
+       export DICT_NAME="$$(basename "$<" ".dir")"; \
+       aspell --dict-dir="$$(realpath $<)" -d "$$DICT_NAME" dump master "$$DICT_NAME" | \
+       aspell --dict-dir="$$(realpath $<)" -l "$$DICT_NAME" expand | \
+       tr -s '[:space:]' '\n' > "$@" && \
+       LC_ALL=C sort -S28G -u -o "$@" "$@"
 
 $(OBJ_DIR)/no.low:
        make $(OBJ_DIR)/nb.low
@@ -82,460 +85,425 @@ $(OBJ_DIR)/pt.low:
        mv $(OBJ_DIR)/pt_PT.low $@
 
 $(ROOT_DICT)/ar.dict: $(OBJ_DIR)/ar.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[ﺏِ ]/ب/g' \
-            -e 's/[ﻍُ]/غ/g' \
-            -e 's/[ﻙ ]/ل/g' \
-            -e 's/[ﻡَ]/م/g' \
-            -e 's/[ﻥَ]/ن/g' \
-            -e 's/[ﻱَﻳّ]/ي/g' | \
-        sort | \
-        uniq > $@
-#   ا ل ن ش ا ش ي بِ ي ي   ب ا ل ن ش ا ش ي بِ ي ي   ب ن ش ا ش ي بِ ي ي   ف ا ل ن ش ا ش ي بِ ي ي   ف ب ا ل ن ش ا ش ي بِ ي ي   ف ب ن ش ا ش ي بِ ي ي   ف ك ا ل ن ش ا ش ي بِ ي ي   ف ك ن ش ا ش ي بِ ي ي   ف ل ل ن ش ا ش ي بِ ي ي   ف ل ن ش ا ش ي بِ ي ي   ف ن ش ا ش ي بِ ي ي   ك ا ل ن ش ا ش ي بِ ي ي   ك ن ش ا ش ي بِ ي ي   ل ل ن ش ا ش ي بِ ي ي   ل ن ش ا ش ي بِ ي ي   ن ش ا ش ي بِ ي ي   و ا ل ن ش ا ش ي بِ ي ي   و ب ا ل ن ش ا ش ي بِ ي ي   و ب ن ش ا ش ي بِ ي ي   و ك ا ل ن ش ا ش ي بِ ي ي   و ك ن ش ا ش ي بِ ي ي   و ل ل ن ش ا ش ي بِ ي ي   و ل ن ش ا ش ي بِ ي ي   و ن ش ا ش ي بِ ي ي 
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[ﺏِ ]/ب/g' \
+           -e 's/[ﻍُ]/غ/g' \
+           -e 's/[ﻙ ]/ل/g' \
+           -e 's/[ﻡَ]/م/g' \
+           -e 's/[ﻥَ]/ن/g' \
+           -e 's/[ﻱَﻳّ]/ي/g' | \
+       sortuniq "$@"
+#   ا ل ن ش ا ش ي بِ ي ي   ب ا ل ن ش ا ش ي بِ ي ي   ب ن ش ا ش ي بِ ي ي   ف ا ل ن ش ا ش ي بِ ي ي   ف ب ا ل ن ش ا ش ي بِ ي ي   ف ب ن ش ا ش ي بِ ي ي   ف ك ا ل ن ش ا ش ي بِ ي ي   ف ك ن ش ا ش ي بِ ي ي   ف ل ل ن ش ا ش ي بِ ي ي   ف ل ن ش ا ش ي بِ ي ي   ف ن ش ا ش ي بِ ي ي   ك ا ل ن ش ا ش ي بِ ي ي   ك ن ش ا ش ي بِ ي ي   ل ل ن ش ا ش ي بِ ي ي   ل ن ش ا ش ي بِ ي ي   ن ش ا ش ي بِ ي ي   و ا ل ن ش ا ش ي بِ ي ي   و ب ا ل ن ش ا ش ي بِ ي ي   و ب ن ش ا ش ي بِ ي ي   و ك ا ل ن ش ا ش ي بِ ي ي   و ك ن ش ا ش ي بِ ي ي   و ل ل ن ش ا ش ي بِ ي ي   و ل ن ش ا ش ي بِ ي ي   و ن ش ا ش ي بِ ي ي
 
 $(ROOT_DICT)/bg.dict: $(OBJ_DIR)/bg.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        grep -v "^[a-zA-Z]" | \
-               tr '[абвгдежзийклмнопрстуфхцчшщъьюя]' '[АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       grep -v "^[a-zA-Z]" | \
+       tr '[абвгдежзийклмнопрстуфхцчшщъьюя]' '[АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/br.dict: $(OBJ_DIR)/br.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[-]" | \
-        grep -v "[^c]'" | \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[-]" | \
+       grep -v "[^c]'" | \
                grep -v "'[^h]" | \
-        sed -e 's/[àâ]/a/g' \
-            -e 's/[éêè]/e/g' \
+       sed -e 's/[àâ]/a/g' \
+           -e 's/[éêè]/e/g' \
                        -e 's/[î]/i/g' \
-            -e 's/[ñ]/n/g' \
-            -e 's/[ô]/o/g' \
-            -e 's/[ûüù]/u/g' | \
-               tr '[abcdefghijklmnopqrstuvwxyz]' '[ABCDEFGHIJKLMNOPQRSTUVWXYZ]' | \
-        sort | \
-        uniq > $@
+           -e 's/[ñ]/n/g' \
+           -e 's/[ô]/o/g' \
+           -e 's/[ûüù]/u/g' | \
+       tr '[abcdefghijklmnopqrstuvwxyz]' '[ABCDEFGHIJKLMNOPQRSTUVWXYZ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/ca.dict: $(OBJ_DIR)/ca.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[áàãÁÀ]/a/g' \
-            -e 's/[éèÉÈ]/e/g' \
-            -e 's/[çÇ]/c/g' \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[áàãÁÀ]/a/g' \
+           -e 's/[éèÉÈ]/e/g' \
+           -e 's/[çÇ]/c/g' \
                        -e 's/[íïÍ]/i/g' \
-            -e 's/[ñ]/n/g' \
-            -e 's/[óöòÓÒ]/o/g' \
-            -e 's/[úüùÚ]/u/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+           -e 's/[ñ]/n/g' \
+           -e 's/[óöòÓÒ]/o/g' \
+           -e 's/[úüùÚ]/u/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/cs.dict: $(OBJ_DIR)/cs.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[äâ]/a/g' \
-            -e 's/[çćĆ]/c/g' \
-            -e 's/[ęë]/e/g' \
-            -e 's/[î]/i/g' \
-            -e 's/[ľĽłĺ]/l/g' \
-            -e 's/[ń]/n/g' \
-            -e 's/[őöŐÖô]/o/g' \
-            -e 's/[śŚ]/s/g' \
-            -e 's/[űüŰÜ]/u/g' \
-            -e 's/[ź]/z/g' | \
-        sed -e 's/á/Á/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' -e 's/ě/Ě/g' \
-            -e 's/í/Í/g' -e 's/ň/Ň/g' -e 's/ó/Ó/g' -e 's/ř/Ř/g' -e 's/š/Š/g' \
-            -e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ů/Ů/g' -e 's/ý/Ý/g' -e 's/ž/Ž/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[äâ]/a/g' \
+           -e 's/[çćĆ]/c/g' \
+           -e 's/[ęë]/e/g' \
+           -e 's/[î]/i/g' \
+           -e 's/[ľĽłĺ]/l/g' \
+           -e 's/[ń]/n/g' \
+           -e 's/[őöŐÖô]/o/g' \
+           -e 's/[śŚ]/s/g' \
+           -e 's/[űüŰÜ]/u/g' \
+           -e 's/[ź]/z/g' | \
+       sed -e 's/á/Á/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' -e 's/ě/Ě/g' \
+           -e 's/í/Í/g' -e 's/ň/Ň/g' -e 's/ó/Ó/g' -e 's/ř/Ř/g' -e 's/š/Š/g' \
+           -e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ů/Ů/g' -e 's/ý/Ý/g' -e 's/ž/Ž/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/cy.dict: $(OBJ_DIR)/cy.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        grep -vi "ph" | \
-        sed -e 's/[âä]/a/g' \
-            -e 's/[êë]/e/g' \
-            -e 's/[îï]/i/g' \
-            -e 's/[ôöò]/o/g' \
-            -e 's/[ûüù]/u/g' \
-            -e 's/[ŵ]/w/g' \
-            -e 's/[ŷ]/y/g' | \
-               tr '[a-z]' '[A-Z]' | \
-               sort | \
-               uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       grep -vi "ph" | \
+       sed -e 's/[âä]/a/g' \
+           -e 's/[êë]/e/g' \
+           -e 's/[îï]/i/g' \
+           -e 's/[ôöò]/o/g' \
+           -e 's/[ûüù]/u/g' \
+           -e 's/[ŵ]/w/g' \
+           -e 's/[ŷ]/y/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/da.dict: $(OBJ_DIR)/da.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[áä]/a/g' \
-            -e 's/[ð]/d/g' \
-            -e 's/[éëè]/e/g' \
-            -e 's/[íì]/i/g' \
-            -e 's/[óöô]/o/g' \
-            -e 's/[ü]/u/g' | \
-        tr '[a-zæøå]' '[A-ZÆØÅ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[áä]/a/g' \
+           -e 's/[ð]/d/g' \
+           -e 's/[éëè]/e/g' \
+           -e 's/[íì]/i/g' \
+           -e 's/[óöô]/o/g' \
+           -e 's/[ü]/u/g' | \
+       tr '[a-zæøå]' '[A-ZÆØÅ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/de.dict: $(OBJ_DIR)/de.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[âà]/a/g' \
-            -e 's/[éê]/e/g' \
-            -e 's/[ñ]/n/g' \
-            -e 's/[œ]/oe/g' \
-            -e 's/[ß]/ss/g' | \
-        tr '[a-zäöü]' '[A-ZÄÖÜ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[âà]/a/g' \
+           -e 's/[éê]/e/g' \
+           -e 's/[ñ]/n/g' \
+           -e 's/[œ]/oe/g' \
+           -e 's/[ß]/ss/g' | \
+       tr '[a-zäöü]' '[A-ZÄÖÜ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/el.dict: $(OBJ_DIR)/el.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[άΆ]/α/g' \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[άΆ]/α/g' \
                    -e 's/[ϐ]/β/g' \
-            -e 's/[έΈ]/ε/g' \
-            -e 's/[ήΉ]/η/g' \
-            -e 's/[ίϊΐΊ]/ι/g' \
-            -e 's/[όΌ]/ο/g' \
-            -e 's/[ς]/σ/g' \
-            -e 's/[ΰϋύΎ]/υ/g' \
-            -e 's/[ϕ]/φ/g' \
-            -e 's/[ώΏ]/ω/g' | \
-               tr '[αβγδεζηθικλμνξοπρστυφχψω]' '[ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ]' | \
-               sort | \
-               uniq > $@
+           -e 's/[έΈ]/ε/g' \
+           -e 's/[ήΉ]/η/g' \
+           -e 's/[ίϊΐΊ]/ι/g' \
+           -e 's/[όΌ]/ο/g' \
+           -e 's/[ς]/σ/g' \
+           -e 's/[ΰϋύΎ]/υ/g' \
+           -e 's/[ϕ]/φ/g' \
+           -e 's/[ώΏ]/ω/g' | \
+       tr '[αβγδεζηθικλμνξοπρστυφχψω]' '[ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/en.dict: $(OBJ_DIR)/en.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[áâàäåÅ]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[éêèë]/e/g' \
-            -e 's/[íîï]/i/g' \
-            -e 's/[ñ]/n/g' \
-            -e 's/[óôöøiÖ]/o/g' \
-            -e 's/[úûüùiÜ]/u/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[áâàäåÅ]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[éêèë]/e/g' \
+           -e 's/[íîï]/i/g' \
+           -e 's/[ñ]/n/g' \
+           -e 's/[óôöøiÖ]/o/g' \
+           -e 's/[úûüùiÜ]/u/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/eo.dict: $(OBJ_DIR)/eo.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'qQwWxXyY-]" | \
-        tr '[a-zĉĝĥĵŝŭ]' '[A-ZĈĜĤĴŜŬ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'qQwWxXyY-]" | \
+       tr '[a-zĉĝĥĵŝŭ]' '[A-ZĈĜĤĴŜŬ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/es.dict: $(OBJ_DIR)/es.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[áÁ]/a/g' \
-            -e 's/[é]/e/g' \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[áÁ]/a/g' \
+           -e 's/[é]/e/g' \
                        -e 's/[í]/i/g' \
-            -e 's/[ó]/o/g' \
-            -e 's/[úü]/u/g' | \
-        tr '[a-zñ]' '[A-ZÑ]' | \
-        sort | \
-        uniq > $@
+           -e 's/[ó]/o/g' \
+           -e 's/[úü]/u/g' | \
+       tr '[a-zñ]' '[A-ZÑ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/et.dict: $(OBJ_DIR)/et.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'qwxQWX-]" | \
-        tr '[a-zäöõüšž]' '[A-ZÄÖÕÜŠŽ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'qwxQWX-]" | \
+       tr '[a-zäöõüšž]' '[A-ZÄÖÕÜŠŽ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/fi.dict: $(OBJ_DIR)/fi.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
                grep -v "[.':-]" | \
-        tr '[a-zäåöšž]' '[A-ZÄÅÖŠŽ]' | \
-        sort | \
-        uniq > $@
+       tr '[a-zäåöšž]' '[A-ZÄÅÖŠŽ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/fr.dict: $(OBJ_DIR)/fr.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[àâä]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[Ééèêë]/e/g' \
-            -e 's/[ïî]/i/g' \
-            -e 's/[ôö]/o/g' \
-            -e 's/[úùûü]/u/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[àâä]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[Ééèêë]/e/g' \
+           -e 's/[ïî]/i/g' \
+           -e 's/[ôö]/o/g' \
+           -e 's/[úùûü]/u/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/ga.dict: $(OBJ_DIR)/ga.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
                grep -v "[.':-]" | \
-        sed -e 's/[áâãÁ]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[éèÉ]/e/g' \
-            -e 's/[íÍ]/i/g' \
-            -e 's/[óöòÓ]/o/g' \
-            -e 's/[úüÚ]/u/g' | \
-        tr '[a-zñ]' '[A-ZÑ]' | \
-        sort | \
-        uniq > $@
+       sed -e 's/[áâãÁ]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[éèÉ]/e/g' \
+           -e 's/[íÍ]/i/g' \
+           -e 's/[óöòÓ]/o/g' \
+           -e 's/[úüÚ]/u/g' | \
+       tr '[a-zñ]' '[A-ZÑ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/he.dict: $(OBJ_DIR)/he.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-               sort | \
-               uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/hr.dict: $(OBJ_DIR)/hr.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-               tr '[a-zćčšž]' '[A-ZĆČŠŽ]' | \
-               sed 's/đ/Đ/g' | \
-               sort | \
-               uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       tr '[a-zćčšž]' '[A-ZĆČŠŽ]' | \
+       sed 's/đ/Đ/g' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/hu.dict: $(OBJ_DIR)/hu.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-               tr '[a-záéóöőúüű]' '[A-ZÁÉÓÖŐÚÜŰ]' | \
-               sort | \
-               uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       tr '[a-záéóöőúüű]' '[A-ZÁÉÓÖŐÚÜŰ]' | \
+       sortuniq "$@"
 
 #grep -v "['ԁԃԂԃ-]"
 $(ROOT_DICT)/hy.dict: $(OBJ_DIR)/hy.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        sed -e 's/ա/Ա/g' -e 's/բ/Բ/g' -e 's/գ/Գ/g' -e 's/դ/Դ/g' -e 's/ե/Ե/g' \
-            -e 's/զ/Զ/g' -e 's/է/Է/g' -e 's/ը/Ը/g' -e 's/թ/Թ/g' -e 's/ժ/Ժ/g' \
-            -e 's/ի/Ի/g' -e 's/լ/Լ/g' -e 's/խ/Խ/g' -e 's/ծ/Ծ/g' -e 's/կ/Կ/g' \
-            -e 's/հ/Հ/g' -e 's/ձ/Ձ/g' -e 's/ղ/Ղ/g' -e 's/ճ/Ճ/g' -e 's/մ/Մ/g' \
-            -e 's/յ/Յ/g' -e 's/ն/Ն/g' -e 's/շ/Շ/g' -e 's/ո/Ո/g' -e 's/չ/Չ/g' \
-            -e 's/պ/Պ/g' -e 's/ջ/Ջ/g' -e 's/ռ/Ռ/g' -e 's/ս/Ս/g' -e 's/վ/Վ/g' \
-            -e 's/տ/Տ/g' -e 's/ր/Ր/g' -e 's/ց/Ց/g' -e 's/ւ/Ւ/g' -e 's/փ/Փ/g' \
-            -e 's/ք/Ք/g' -e 's/օ/Օ/g' -e 's/ֆ/Ֆ/g' -e 's/ու/ՈՒ/g' \
-            -e "s/'//g" | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       sed -e 's/ա/Ա/g' -e 's/բ/Բ/g' -e 's/գ/Գ/g' -e 's/դ/Դ/g' -e 's/ե/Ե/g' \
+           -e 's/զ/Զ/g' -e 's/է/Է/g' -e 's/ը/Ը/g' -e 's/թ/Թ/g' -e 's/ժ/Ժ/g' \
+           -e 's/ի/Ի/g' -e 's/լ/Լ/g' -e 's/խ/Խ/g' -e 's/ծ/Ծ/g' -e 's/կ/Կ/g' \
+           -e 's/հ/Հ/g' -e 's/ձ/Ձ/g' -e 's/ղ/Ղ/g' -e 's/ճ/Ճ/g' -e 's/մ/Մ/g' \
+           -e 's/յ/Յ/g' -e 's/ն/Ն/g' -e 's/շ/Շ/g' -e 's/ո/Ո/g' -e 's/չ/Չ/g' \
+           -e 's/պ/Պ/g' -e 's/ջ/Ջ/g' -e 's/ռ/Ռ/g' -e 's/ս/Ս/g' -e 's/վ/Վ/g' \
+           -e 's/տ/Տ/g' -e 's/ր/Ր/g' -e 's/ց/Ց/g' -e 's/ւ/Ւ/g' -e 's/փ/Փ/g' \
+           -e 's/ք/Ք/g' -e 's/օ/Օ/g' -e 's/ֆ/Ֆ/g' -e 's/ու/ՈՒ/g' \
+           -e "s/'//g" | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/it.dict: $(OBJ_DIR)/it.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'-]" | \
-        sed -e 's/[àâ]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[éè]/e/g' \
-            -e 's/[ì]/i/g' \
-            -e 's/[òiô]/o/g' \
-            -e 's/[ù]/u/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'-]" | \
+       sed -e 's/[àâ]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[éè]/e/g' \
+           -e 's/[ì]/i/g' \
+           -e 's/[òiô]/o/g' \
+           -e 's/[ù]/u/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/is.dict: $(OBJ_DIR)/is.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
                grep -v "[.'-]" | \
-               tr '[a-záæðéíóöúýþ]' '[A-ZÁÆÐÉÍÓÖÚÝÞ]' | \
-               sort | \
-               uniq > $@
+               tr '[a-záæðéíóöúýþ]' '[A-ZÁÆÐÉÍÓÖÚÝÞ]' | sortuniq "$@"
 
 $(ROOT_DICT)/lv.dict: $(OBJ_DIR)/lv.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
                grep -v "[.'-]" | \
-               tr '[a-zāčēģīķļņšūž]' '[A-ZĀČĒĢĪĶĻŅŠŪŽ]' | \
-               sort | \
-               uniq > $@
+               tr '[a-zāčēģīķļņšūž]' '[A-ZĀČĒĢĪĶĻŅŠŪŽ]' | sortuniq "$@"
 
 $(ROOT_DICT)/nl.dict: $(OBJ_DIR)/nl.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[1-9+/' .-]" | \
-        sed -e 's/[áäâàÅ]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[éëèê]/e/g' \
-            -e 's/[íïî]/i/g' \
-            -e 's/[ñ]/n/g' \
-            -e 's/[óöô]/o/g' \
-            -e 's/[úüûùÜ]/u/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[1-9+/' .-]" | \
+       sed -e 's/[áäâàÅ]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[éëèê]/e/g' \
+           -e 's/[íïî]/i/g' \
+           -e 's/[ñ]/n/g' \
+           -e 's/[óöô]/o/g' \
+           -e 's/[úüûùÜ]/u/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/no.dict: $(OBJ_DIR)/no.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[.'\"-]" | \
-        sed -e 's/[áäÄ]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[ð]/d/g' \
-            -e 's/[éëèêÉ]/e/g' \
-            -e 's/[íì]/i/g' \
-            -e 's/[óöôò]/o/g' \
-            -e 's/[ü]/u/g' | \
-        tr '[a-zæøå]' '[A-ZÆØÅ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[.'\"-]" | \
+       sed -e 's/[áäÄ]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[ð]/d/g' \
+           -e 's/[éëèêÉ]/e/g' \
+           -e 's/[íì]/i/g' \
+           -e 's/[óöôò]/o/g' \
+           -e 's/[ü]/u/g' | \
+       tr '[a-zæøå]' '[A-ZÆØÅ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/pl.dict: $(OBJ_DIR)/pl.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[ä]/a/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[é]/e/g' \
-            -e 's/[i]/i/g' \
-            -e 's/[ö]/o/g' \
-            -e 's/[šŠ]/s/g' \
-            -e 's/[û]/u/g' | \
-        tr '[a-złąęóśżćńź]' '[A-ZŁĄĘÓŚŻĆŃŹ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[ä]/a/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[é]/e/g' \
+           -e 's/[i]/i/g' \
+           -e 's/[ö]/o/g' \
+           -e 's/[šŠ]/s/g' \
+           -e 's/[û]/u/g' | \
+       tr '[a-złąęóśżćńź]' '[A-ZŁĄĘÓŚŻĆŃŹ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/pt.dict: $(OBJ_DIR)/pt.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[áãâàÁÂ]/a/g' \
-            -e 's/[éêèÉ]/e/g' \
-            -e 's/[íîÍ]/i/g' \
-            -e 's/[óôõÓ]/o/g' \
-            -e 's/[úüÚ]/u/g' | \
-        tr '[a-zç]' '[A-ZÇ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[áãâàÁÂ]/a/g' \
+           -e 's/[éêèÉ]/e/g' \
+           -e 's/[íîÍ]/i/g' \
+           -e 's/[óôõÓ]/o/g' \
+           -e 's/[úüÚ]/u/g' | \
+       tr '[a-zç]' '[A-ZÇ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/ro.dict: $(OBJ_DIR)/ro.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
                sed -e 's/[áâăÂĂ]/a/g' \
-            -e 's/[éè]/e/g' \
-            -e 's/[íîÎ]/i/g' \
-            -e 's/[șȘ]/s/g' \
-            -e 's/[țȚ]/t/g' \
-            -e 's/[ü]/u/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+           -e 's/[éè]/e/g' \
+           -e 's/[íîÎ]/i/g' \
+           -e 's/[șȘ]/s/g' \
+           -e 's/[țȚ]/t/g' \
+           -e 's/[ü]/u/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/ru.dict: $(OBJ_DIR)/ru.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/а/А/g' -e 's/б/Б/g' -e 's/в/В/g' -e 's/г/Г/g' -e 's/д/Д/g' \
-            -e 's/е/Е/g' -e 's/ё/Ё/g' -e 's/ж/Ж/g' -e 's/з/З/g' -e 's/и/И/g' \
-            -e 's/й/Й/g' -e 's/к/К/g' -e 's/л/Л/g' -e 's/м/М/g' -e 's/н/Н/g' \
-            -e 's/о/О/g' -e 's/п/П/g' -e 's/р/Р/g' -e 's/с/С/g' -e 's/т/Т/g' \
-            -e 's/у/У/g' -e 's/ф/Ф/g' -e 's/х/Х/g' -e 's/ц/Ц/g' -e 's/ч/Ч/g' \
-            -e 's/ш/Ш/g' -e 's/щ/Щ/g' -e 's/ъ/Ъ/g' -e 's/ы/Ы/g' -e 's/ь/Ь/g' \
-            -e 's/э/Э/g' -e 's/ю/Ю/g' -e 's/я/Я/g' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/а/А/g' -e 's/б/Б/g' -e 's/в/В/g' -e 's/г/Г/g' -e 's/д/Д/g' \
+           -e 's/е/Е/g' -e 's/ё/Ё/g' -e 's/ж/Ж/g' -e 's/з/З/g' -e 's/и/И/g' \
+           -e 's/й/Й/g' -e 's/к/К/g' -e 's/л/Л/g' -e 's/м/М/g' -e 's/н/Н/g' \
+           -e 's/о/О/g' -e 's/п/П/g' -e 's/р/Р/g' -e 's/с/С/g' -e 's/т/Т/g' \
+           -e 's/у/У/g' -e 's/ф/Ф/g' -e 's/х/Х/g' -e 's/ц/Ц/g' -e 's/ч/Ч/g' \
+           -e 's/ш/Ш/g' -e 's/щ/Щ/g' -e 's/ъ/Ъ/g' -e 's/ы/Ы/g' -e 's/ь/Ь/g' \
+           -e 's/э/Э/g' -e 's/ю/Ю/g' -e 's/я/Я/g' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/sk.dict: $(OBJ_DIR)/sk.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[ë]/e/g' | \
-        sed -e 's/á/Á/g' -e 's/ä/Ä/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' \
-            -e 's/ě/Ě/g' -e 's/í/Í/g' -e 's/ľ/Ľ/g' -e 's/ĺ/Ĺ/g' -e 's/ň/Ň/g' \
-            -e 's/ô/Ô/g' -e 's/ó/Ó/g' -e 's/ö/Ö/g' -e 's/ŕ/Ŕ/g' -e 's/ř/Ř/g' \
-            -e 's/š/Š/g' -e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ü/Ü/g' -e 's/ý/Ý/g' \
-            -e 's/ž/Ž/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[ë]/e/g' | \
+       sed -e 's/á/Á/g' -e 's/ä/Ä/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' \
+           -e 's/ě/Ě/g' -e 's/í/Í/g' -e 's/ľ/Ľ/g' -e 's/ĺ/Ĺ/g' -e 's/ň/Ň/g' \
+           -e 's/ô/Ô/g' -e 's/ó/Ó/g' -e 's/ö/Ö/g' -e 's/ŕ/Ŕ/g' -e 's/ř/Ř/g' \
+           -e 's/š/Š/g' -e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ü/Ü/g' -e 's/ý/Ý/g' \
+           -e 's/ž/Ž/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/sl.dict: $(OBJ_DIR)/sl.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[áâȁ]/a/g' \
-            -e 's/[ćĆ]/c/g' \
-            -e 's/[éȇȅ]/e/g' \
-            -e 's/[đĐ]/d/g' \
-            -e 's/[íȋȉ]/i/g' \
-            -e 's/[óȏȍö]/o/g' \
-            -e 's/[ŕȓ]/r/g' \
-            -e 's/[úȗȕü]/u/g' | \
-        sed -e 's/č/Č/g' -e 's/š/Š/g' -e 's/ž/Ž/g' | \
-        tr '[a-z]' '[A-Z]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[áâȁ]/a/g' \
+           -e 's/[ćĆ]/c/g' \
+           -e 's/[éȇȅ]/e/g' \
+           -e 's/[đĐ]/d/g' \
+           -e 's/[íȋȉ]/i/g' \
+           -e 's/[óȏȍö]/o/g' \
+           -e 's/[ŕȓ]/r/g' \
+           -e 's/[úȗȕü]/u/g' | \
+       sed -e 's/č/Č/g' -e 's/š/Š/g' -e 's/ž/Ž/g' | \
+       tr '[a-z]' '[A-Z]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/sv.dict: $(OBJ_DIR)/sv.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "['-]" | \
-        sed -e 's/[æ]/ae/g' \
-            -e 's/[ç]/c/g' \
-            -e 's/[é]/e/g' \
-            -e 's/[ü]/u/g' | \
-        tr '[a-zåäö]' '[A-ZÅÄÖ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "['-]" | \
+       sed -e 's/[æ]/ae/g' \
+           -e 's/[ç]/c/g' \
+           -e 's/[é]/e/g' \
+           -e 's/[ü]/u/g' | \
+       tr '[a-zåäö]' '[A-ZÅÄÖ]' | \
+       sortuniq "$@"
 
 $(ROOT_DICT)/uk.dict: $(OBJ_DIR)/uk.low $(DEPEND)
-       echo Building $@ from $<
-       cat $< | \
-        grep -v '^.$$' | \
-        grep -v "[-]" | \
-        tr '[абвгґдеєжзиіїйклмнопрстуфхцчшщьюя]' '[АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ]' | \
-        sort | \
-        uniq > $@
+       @$(DICT_RULE_PRELUDE); \
+       cat "$<" | \
+       grep -v '^.$$' | \
+       grep -v "[-]" | \
+       tr '[абвгґдеєжзиіїйклмнопрстуфхцчшщьюя]' '[АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ]' | \
+       sortuniq "$@"
 
 CHECKER = cat $(1) | \
     grep -v "^[$(2)]*$$" | egrep -v "$(3)" && exit 1 || echo "$< is correct"
@@ -624,3 +592,6 @@ check-uk:$(ROOT_DICT)/uk.dict
 
 check-%:$(ROOT_DICT)/%.dict
        $(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZ,~)
+
+clean:
+       rm -rf "$(OBJ_DIR)"
index 8d3ee32002b00466b7a6542c4b18f27bb0fbc0d7..8e4292f010c94c3d9c0f9e0d1506b225e6f5fb58 100644 (file)
@@ -182,7 +182,7 @@ msgid  "Incorrect dictionary file."
 msgstr "Dictionnaire incorrect."
 
 msgid  "Can't load dictionary file."
-msgstr "Impossible de charger de dictionnaire"
+msgstr "Impossible de charger le dictionnaire"
 
 msgid  "Enable spell checker"
 msgstr "Activer le vérificateur orthographique"
index beba4ee7bb2a2a13b8cb47c38c724281365f3562..2a69af54d4d8ee5bd991065d40970f4edebebce2 100644 (file)
@@ -17,6 +17,9 @@ window.TrivabbleConf = {
     // to tweak only if your webserver is shared with other conflicting resources at / ( ex: yunohost integration )
     APP_PATH: "",
 
+    // Whether Check spelling is enabled (dictionaries must be downloaded on the server before enabling this option
+    ENABLE_CHECK_SPELLING: false,
+
     // I don't like trailing commas, here is a nice message for you reading this file :-)
     HAVE_FUN: true
 };
index 22d6993e83cf937d62fa512fdb48eec2ca8bb7dd..be8dd23787aba7082446a19be22da9042a6f66de 100644 (file)
@@ -53,7 +53,7 @@
                 <div id="prefs-sound">
                     <p><label><input type="checkbox" id="tiles-sound" checked="checked" /><span data-l10n="text-content">Sound of the tiles</span></label></p>
                     <p><label><input type="checkbox" id="msg-sound" checked="checked" /><span data-l10n="text-content">Sound of messages</span></label></p>
-                    <p><label><input type="checkbox" id="enable-spell-checker" /> <span data-l10n="text-content">Enable spell checker</span></label></p>
+                    <p><label><input type="checkbox" id="enable-spell-checker" style="display:none" /> <span data-l10n="text-content">Enable spell checker</span></label></p>
                 </div>
             </div>
         </div>
index a684d014d9fc9dd8e4b7b28560cbdb501f42c8be..bb50e36adef9abddb0556ec6729e0aca2030eb27 100644 (file)
@@ -42,7 +42,7 @@
     setConf("ENABLE_EVENT_SOURCE",  true);
     setConf("MAX_WEBSOCKET_ERRORS", 1);
     setConf("APP_PATH",             "");
-    setConf("SPELL_CHECKER",        "false");
+    setConf("ENABLE_SPELL_CHECKER", false);
 
     const _ = (window.libD && libD.l10n) ? libD.l10n() : function (s) {
         return s;
         }
     }
 
-    function checkSpellCheckerState(code) {
-        if (code !== null) {
-            localStorage.spellChecker = code;
+    function setSpellCheckerState(enabled) {
+        if (enabled !== null) {
+            localStorage.spellCheckerEnabled = enabled.toString();
         }
-        if (localStorage.spellChecker === "false") {
+
+        if (localStorage.spellCheckerEnabled === "false") {
             document.getElementById("enable-spell-checker").checked = false;
             document.getElementById("check-spelling").style.display = "none";
         } else {
             document.getElementById("enable-spell-checker").checked = true;
-            document.getElementById("check-spelling").style.display = "block";
+            document.getElementById("check-spelling").style.display = "";
         }
     }
 
     function downloadDictionary(code) {
-        if (localStorage.spellChecker === code) {
+        if (localStorage.spellCheckerEnabled === code) {
             return;
         }
 
         file.open("GET", "dict/" + code + ".dict", true);
         file.onreadystatechange = function () {
             if (file.readyState === 4) {
-                if (Number(file.status) === 200) {
+                if (file.status === 200) {
                     try {
                         dictionary = file.responseText.split("\n");
-                        checkSpellCheckerState(code);
+                        setSpellCheckerState(code);
                     } catch (e) {
                         myAlert(_("Incorrect dictionary file."));
-                        checkSpellCheckerState("false");
+                        setSpellCheckerState(false);
                     }
                 } else {
                     myAlert(_("Can't load dictionary file."));
-                    checkSpellCheckerState("false");
+                    setSpellCheckerState(false);
                 }
             }
         };
                     downloadDictionary(localStorage.trivabbleBoardLang);
                 },
                 function () {
-                    checkSpellCheckerState("false");
+                    setSpellCheckerState(false);
                 });
         } else {
-            checkSpellCheckerState("false");
+            setSpellCheckerState(false);
         }
     }
 
             case "boardLang":
                 localStorage.trivabbleBoardLang = value;
                 document.getElementById("board-lang").value = value;
-                if (localStorage.spellChecker !== "false") {
+                if (localStorage.spellCheckerEnabled !== "false") {
                     downloadDictionary(value);
                 }
                 break;
     }
 
     function searchWordInLine(row, col, incRow, incCol) {
-        
         const initLetter = getLetterFromBoard(row, col);
 
         /* Look for first letter in line */
         }
         return (word.letters === initLetter) ? null : word;
     }
-    
+
     function isNewWord(newWord, words) {
         if (newWord === null) {
             return false;
     }
 
     function checkSpelling() {
-        if (localStorage.spellChecker === false) {
+        if (localStorage.spellCheckerEnabled === "false") {
             return;
         }
 
     }
 
     function initSpellChecker() {
-        if (!Object.prototype.hasOwnProperty.call(localStorage, "spellChecker")) {
-            localStorage.spellChecker = Conf.SPELL_CHECKER;
+        if (!localStorage.spellCheckerEnabled) {
+            localStorage.spellCheckerEnabled = Conf.ENABLE_SPELL_CHECKER.toString();
         }
 
         document.getElementById("enable-spell-checker").onclick = enableSpellChecker;
 
-        if (localStorage.spellChecker === "false") {
-            checkSpellCheckerState("false");
+        if (localStorage.spellCheckerEnabled === "false") {
+            setSpellCheckerState(false);
         } else {
-            const spellChecker = localStorage.spellChecker;
-            localStorage.spellChecker = "false";
+            const spellChecker = localStorage.spellCheckerEnabled;
+            localStorage.spellCheckerEnabled = "false";
             downloadDictionary(spellChecker);
         }
     }
             document.getElementById("board-lang").value = localStorage.trivabbleBoardLang;
         }
 
-        startGame(localStorage.trivabbleGameNumber, localStorage.trivabbleBoardLang);
+        startGame(localStorage.trivabbleGameNumber);
     }
 
     function initLang() {