diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 0e06ce0..85b2c31 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -11,6 +11,14 @@ This is not enforced, and contributions with incorrect formatting will be accept ## Translations +### Contributing to an existing translation + +* Go [here](https://github.com/sanderland/katrain/blob/master/katrain/i18n/locales/) and locate the `.po` file for your language. + Alternatively, find the same file in the branch for the next version. +* Correct the relevant `msgstr` entries. + +### Adding a translation + Adding a translation requires making a new `.po` file with entries for that languages. * Copy the [English .po file](https://github.com/sanderland/katrain/blob/master/katrain/i18n/locales/en/LC_MESSAGES/katrain.po) @@ -19,19 +27,6 @@ Adding a translation requires making a new `.po` file with entries for that lang * The information at the top of the file should also not be translated. You can send me the resulting `.po` file and I will integrate it into the program. - -For those who have some python experience as well, you can: - -* Replicate the directory structure `katrain/i18n//LC_MESSAGES/katrain.po`. -* Run `python i18.py` which will generate the `.mo` files and check for any errors. -* Find `gui.kv` and add a button near the others: - ``` - LangButton: - icon: 'img/flags/flag-.png' - on_press: app.language = '' - ``` -* The language should now show up in the app. -* Pull request your changes to the latest minor version branch. # Contributors @@ -53,6 +48,7 @@ Many thanks to these additional authors: * "kaorahi" for bug fixes and SGF parser improvements. * "ajkenny84" for the red-green colourblind theme. * Lukasz Wierzbowski for the ability to paste urls for sgfs and helping fix alt-gr issues. +* Carton He for a fix to handling empty komi values in sgfs. ## Translators diff --git a/README.md b/README.md index 1ec51f6..7fa6f9a 100644 --- a/README.md +++ b/README.md @@ -177,15 +177,15 @@ Keyboard shortcuts are shown with **[key]**. In addition to shortcuts mentioned above and those shown in the main menu: * **[Shift]**: Open the main menu. -* **[~]** or **[ ` ]** or **[m]**: Cycles through more minimalistic UI modes. +* **[~]** or **[ ` ]** or **[f12]**: Cycles through more minimalistic UI modes. * **[p]**: Pass -* **[b]**: Pause/Resume timer +* **[pause]**: Pause/Resume timer * **[arrow left]** or **[z]**: Undo move. Hold alt for 10 moves at a time, or ctrl to skip to the start. * **[arrow right]** or **[x]**: Redo move. Hold alt for 10 moves at a time, or ctrl to skip to the end. * **[arrow up/down]** Switch branch, as would be expected from the move tree. * **[home/end]** Go to the beginning/end of the game. * **[pageup]** Make the currently selected node the main branch -* **[ctrl-delete]** Delete current node. +* **[Ctrl-delete]** Delete current node. * **[c]** Collapse/Uncollapse the branch from the current node to the previous branching point. * **[b]** Go back to the previous branching point. * **[n]** As in clicking the red arrow, go to one move before the next mistake (orange or worse) by a human player. diff --git a/katrain/__main__.py b/katrain/__main__.py index 80608a3..6989370 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -64,7 +64,8 @@ from katrain.core.constants import ( STATUS_ERROR, STATUS_INFO, PLAYING_NORMAL, - PLAYER_HUMAN, SGF_INTERNAL_COMMENTS_MARKER, + PLAYER_HUMAN, + SGF_INTERNAL_COMMENTS_MARKER, ) from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup, I18NPopup, SaveSGFPopup from katrain.core.base_katrain import KaTrainBase @@ -545,9 +546,9 @@ class KaTrainGui(Screen, KaTrainBase): self.nav_drawer.set_state("toggle") elif keycode[1] == "spacebar": self.toggle_continuous_analysis() - elif keycode[1] == "b" and ctrl_pressed: + elif keycode[1] in ["pause", "break", "f15"] and not ctrl_pressed: self.controls.timer.paused = not self.controls.timer.paused - elif keycode[1] in ["`", "~", "m"] and ctrl_pressed: + elif keycode[1] in ["`", "~", "f12"]: self.zen = (self.zen + 1) % 3 elif keycode[1] in ["left", "z"]: self("undo", 1 + (alt_pressed or shift_pressed) * 9 + (ctrl_pressed and not alt_pressed) * 999) diff --git a/katrain/core/game.py b/katrain/core/game.py index f995d12..ceab62f 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -20,7 +20,8 @@ from katrain.core.constants import ( STATUS_ERROR, STATUS_INFO, STATUS_TEACHING, - VERSION, SGF_INTERNAL_COMMENTS_MARKER, + VERSION, + SGF_INTERNAL_COMMENTS_MARKER, ) from katrain.core.engine import KataGoEngine from katrain.core.game_node import GameNode @@ -407,7 +408,9 @@ class Game: x_properties["RE"] = self.end_result x_properties["KTV"] = ANALYSIS_FORMAT_VERSION self.root.properties = {**root_properties, **{k: [v] for k, v in x_properties.items()}} - player_names = {bw: re.sub(r"[\u200b\u3164'<>:\"/\\|?*]", "", self.root.get_property("P" + bw, bw)) for bw in "BW"} + player_names = { + bw: re.sub(r"[\u200b\u3164'<>:\"/\\|?*]", "", self.root.get_property("P" + bw, bw)) for bw in "BW" + } base_game_name = f"{PROGRAM_NAME}_{player_names['B']} vs {player_names['W']}" return f"{base_game_name} {self.game_id}.sgf" @@ -507,7 +510,7 @@ class Game: priority = -1_000_000_000 elif mode in ["equalize", "alternative", "local"]: if not cn.analysis_complete and mode != "local": - self.katrain.controls.set_status(i18n._("wait-before-equalize"), STATUS_INFO, self.current_node) + self.katrain.controls.set_status(i18n._("wait-before-extra-analysis"), STATUS_INFO, self.current_node) return if mode == "alternative": # also do a quick update on current candidates so it doesn't look too weird self.katrain.controls.set_status(i18n._("alternative analysis"), STATUS_ANALYSIS) @@ -530,13 +533,14 @@ class Game: cn = self.current_node count = 0 if not cn.analysis_exists: + self.katrain.controls.set_status(i18n._("wait-before-extra-analysis"), STATUS_INFO, cn) return def analyze_and_play_policy(node): nonlocal count, cn cand = node.candidate_moves if self.katrain.game is not self: - return # a new game happened + return # a new game happened if cand: move = Move.from_gtp(cand[0]["move"], player=node.next_player) else: @@ -544,8 +548,9 @@ class Game: move = polmoves[0][1] if polmoves else Move(None) if move.is_pass: - self.set_current_node(node) - self.katrain.controls.set_status("", STATUS_INFO) + if self.current_node == cn: + self.set_current_node(node) + self.katrain.controls.set_status("", STATUS_INFO, cn) return count += 1 new_node = GameNode(parent=node, move=move) @@ -554,7 +559,7 @@ class Game: cn.add_shortcut(new_node) self.katrain.controls.move_tree.redraw_tree_trigger() - self.katrain.controls.set_status(i18n._("playtoend:status").format(num_moves=count), STATUS_INFO) + self.katrain.controls.set_status(i18n._("playtoend:status").format(num_moves=count), STATUS_INFO, cn) def set_analysis(result, _partial): new_node.set_analysis(result) diff --git a/katrain/gui/badukpan.py b/katrain/gui/badukpan.py index f1cd02a..4a610d0 100644 --- a/katrain/gui/badukpan.py +++ b/katrain/gui/badukpan.py @@ -502,6 +502,7 @@ class BadukPanWidget(Widget): ] top_move_coords = None + child_moves = {c.move.gtp() for c in current_node.children if c.move} if hint_moves: low_visits_threshold = katrain.config("trainer/low_visits", 25) top_moves_show = [ @@ -519,7 +520,11 @@ class BadukPanWidget(Widget): scale = HINT_SCALE text_on = True alpha = HINTS_ALPHA - if move_dict["visits"] < low_visits_threshold and not engine_best_move: + if ( + move_dict["visits"] < low_visits_threshold + and not engine_best_move + and not move_dict["move"] in child_moves + ): scale = UNCERTAIN_HINT_SCALE text_on = False alpha = HINTS_LO_ALPHA diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index 27d8a8e..4fcee19 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -253,11 +253,10 @@ class NewGamePopup(QuickConfigGui): def normalized_rules(self): rules = self.katrain.game.root.get_property("RU", "japanese").strip().lower() for abbr, name in self.katrain.engine.RULESETS_ABBR: - if abbr==rules or abbr==rules: + if abbr == rules or abbr == rules: return name - - def update_playerinfo(self,*args): + def update_playerinfo(self, *args): for bw, player_setup in self.player_setup.players.items(): name = self.player_name[bw].text if name: @@ -274,7 +273,6 @@ class NewGamePopup(QuickConfigGui): if rules is not None: self.rules_spinner.select_key(rules.strip()) - def update_config(self, save_to_file=True): super().update_config(save_to_file=save_to_file) self.katrain.log(f"New game settings: {self.katrain.config('game')}", OUTPUT_DEBUG) @@ -288,11 +286,15 @@ class NewGamePopup(QuickConfigGui): props = self.collect_properties(self) root = self.katrain.game.root changed = False - for k, currentval, newval in [("RU",self.normalized_rules(), props["game/rules"]), ("KM", root.komi, props["game/komi"])]: - if currentval !=newval: + for k, currentval, newval in [ + ("RU", self.normalized_rules(), props["game/rules"]), + ("KM", root.komi, props["game/komi"]), + ]: + if currentval != newval: changed = True self.katrain.log( - f"Property {k} changed from {currentval} to {newval}, triggering re-analysis of entire game.", OUTPUT_INFO + f"Property {k} changed from {currentval} to {newval}, triggering re-analysis of entire game.", + OUTPUT_INFO, ) self.katrain.game.root.set_property(k, newval) self.update_playerinfo() diff --git a/katrain/gui/widgets/movetree.py b/katrain/gui/widgets/movetree.py index 99d1728..ecd53f1 100644 --- a/katrain/gui/widgets/movetree.py +++ b/katrain/gui/widgets/movetree.py @@ -143,8 +143,8 @@ class MoveTreeCanvas(Widget): def children_with_shortcuts(move): shortcuts = move.shortcuts_to - via = [v for m, v in shortcuts] # children that are shortcut - return [m for m in move.ordered_children if m not in via] + [m for m, v in shortcuts] + via = {v: m for m, v in shortcuts} # children that are shortcut + return [m if m not in via else via[m] for m in move.ordered_children] self.move_pos = {root: (0, 0)} stack = children_with_shortcuts(root)[::-1] diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo index b7e88de..e2d7c20 100644 Binary files a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po index 55d9acf..842ae99 100644 --- a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po @@ -415,7 +415,7 @@ msgstr "保存AI设置" msgid "sgf written" msgstr "带分析的SGF文件保存到 {file_name}" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "优化前等待初始分析完成" msgid "Copied SGF to clipboard." diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo index 6118c39..62e3473 100644 Binary files a/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po index b956b6f..01a7197 100644 --- a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po @@ -425,7 +425,7 @@ msgstr "AI Einstellungen aktualisieren" msgid "sgf written" msgstr "SGF mit Analyse gespeichert unter {file_name}" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "" "Auf Abschluss der Initialanalyse warten, bevor eine Verfeinerung erfolgt." diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo index 2c3ffbf..7894478 100644 Binary files a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po index 286c85b..918a962 100644 --- a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po @@ -553,7 +553,7 @@ msgstr "Update AI Settings" msgid "sgf written" msgstr "SGF with analysis written to {file_name}" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "Wait for initial analysis to complete before requesting a refinement." msgid "Copied SGF to clipboard." diff --git a/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo index 139dbc9..5f67881 100644 Binary files a/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/es/LC_MESSAGES/katrain.po b/katrain/i18n/locales/es/LC_MESSAGES/katrain.po index 44a1d58..93c0209 100644 --- a/katrain/i18n/locales/es/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/es/LC_MESSAGES/katrain.po @@ -430,7 +430,7 @@ msgstr "Actualizar conf IA" msgid "sgf written" msgstr "SGF con análisis escrito en {file_name}" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "" "Esperar completar análisis inicial antes de solicitar un refinamiento." diff --git a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo index f9a8094..3fddf6c 100644 Binary files a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po index 10f99d3..9eaa760 100644 --- a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po @@ -476,7 +476,7 @@ msgstr "Mettre à jour" msgid "sgf written" msgstr "Analyse SGF rédigée dans {file_name}" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "Attendez la fin de l'analyse en cours avant de l'approfondir." msgid "Copied SGF to clipboard." diff --git a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo index 6d6ff7c..e9dafa4 100644 Binary files a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po index fd8ddae..b0e571a 100644 --- a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po @@ -452,7 +452,7 @@ msgstr "AI設定を更新" msgid "sgf written" msgstr "分析結果入りSGFを{file_name}に保存" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "初期分析が完了しないと均等分析はできません" msgid "Copied SGF to clipboard." diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo index f993125..366a5ef 100644 Binary files a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po index c04f90b..c8d1081 100644 --- a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po @@ -424,7 +424,7 @@ msgstr "인공지능 설정 갱신" msgid "sgf written" msgstr "SGF와 분석 결과를 {file_name}에 기록했습니다." -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "추가적인 분석을 요청하기 전에, 먼저 일차적인 분석이 끝날 때까지 기다려 주십시오." msgid "Copied SGF to clipboard." diff --git a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo index 951f6cc..0bc8dd4 100644 Binary files a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po index 9955655..92f3c42 100644 --- a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po @@ -450,7 +450,7 @@ msgstr "Сохранить настройки ИИ" msgid "sgf written" msgstr "SGF с анализом сохранён в {file_name}" -msgid "wait-before-equalize" +msgid "wait-before-extra-analysis" msgstr "Дождитесь начального анализа перед запросом уточнений." msgid "Copied SGF to clipboard."