i18n better
This commit is contained in:
1 parent
4ad46a201b
commit
c92d144519
14 files changed
+100
-52
No files matched your search
+1
-1
@@ -2,7 +2,7 @@ Primary author and project maintainer (https://github.com/sanderland/katrain):
|
||||
Sander Land
|
||||
|
||||
Many thanks to these additional authors:
|
||||
"Kameone" - for design of the v1.1 UI, MacOS installation instructions, and suggestions for improvements.
|
||||
Matthew Allred ("Kameone") for design of the v1.1 UI and providing MacOS installation instructions.
|
||||
|
||||
Additional thanks to:
|
||||
"Dontbtme" for detailed feedback and early testing of v1.0.
|
||||
|
||||
+3
-2
@@ -31,7 +31,6 @@ class TestBox(GridLayout):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class BackgroundMixin(Widget):
|
||||
background_color = ListProperty([0, 0, 0, 0])
|
||||
background_radius = NumericProperty(0)
|
||||
@@ -64,7 +63,8 @@ class LeftButtonBehavior(ButtonBehavior): # stops buttons etc activating on rig
|
||||
def on_left_press(self):
|
||||
pass
|
||||
|
||||
class PauseButton(LeftButtonBehavior,Widget):
|
||||
|
||||
class PauseButton(LeftButtonBehavior, Widget):
|
||||
active = BooleanProperty(True)
|
||||
active_line_color = WHITE
|
||||
inactive_line_color = WHITE
|
||||
@@ -78,6 +78,7 @@ class PauseButton(LeftButtonBehavior,Widget):
|
||||
def on_left_press(self):
|
||||
self.active = not self.active
|
||||
|
||||
|
||||
KV = """
|
||||
#:set LIGHTGREY [0.7,0.7,0.7,1]
|
||||
#:set WHITE [1,1,1,1]
|
||||
|
||||
+12
-1
@@ -24,7 +24,18 @@ from kivy.uix.screenmanager import Screen
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from katrain.core.ai import ai_move
|
||||
from katrain.core.utils import DEFAULT_LANGUAGE, OUTPUT_DEBUG, OUTPUT_ERROR, OUTPUT_EXTRA_DEBUG, OUTPUT_INFO, OUTPUT_KATAGO_STDERR, find_package_resource, i18n, MODE_PLAY, switch_lang, i18n_font
|
||||
from katrain.core.utils import (
|
||||
DEFAULT_LANGUAGE,
|
||||
OUTPUT_DEBUG,
|
||||
OUTPUT_ERROR,
|
||||
OUTPUT_EXTRA_DEBUG,
|
||||
OUTPUT_INFO,
|
||||
OUTPUT_KATAGO_STDERR,
|
||||
find_package_resource,
|
||||
i18n,
|
||||
MODE_PLAY,
|
||||
switch_lang,
|
||||
)
|
||||
from katrain.core.engine import KataGoEngine
|
||||
from katrain.core.game import Game, IllegalMoveException, KaTrainSGF
|
||||
from katrain.core.sgf_parser import Move, ParseError
|
||||
|
||||
+31
-27
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import sys
|
||||
from typing import Any, List, Tuple
|
||||
from typing import Any, List, Tuple, Callable
|
||||
|
||||
from kivy.event import EventDispatcher
|
||||
from kivy.lang import Observable
|
||||
@@ -9,6 +9,9 @@ import gettext
|
||||
from kivy.properties import StringProperty
|
||||
from kivy.uix.label import Label
|
||||
from kivy.uix.textinput import TextInput
|
||||
from kivymd.uix.label import MDIcon
|
||||
|
||||
from katrain.gui.style import DEFAULT_FONT
|
||||
|
||||
try:
|
||||
import importlib.resources as pkg_resources
|
||||
@@ -54,69 +57,70 @@ def find_package_resource(path):
|
||||
return path # absolute path
|
||||
|
||||
|
||||
class LangFont(EventDispatcher):
|
||||
font_name = StringProperty('')
|
||||
|
||||
|
||||
DEFAULT_FONT = "fonts/NotoSans-Regular.ttf"
|
||||
FONTS = {'ko': "fonts/NotoSansKR-Regular.otf"}
|
||||
font_name = StringProperty('')
|
||||
def __init__(self,lang,**kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.switch_lang(lang)
|
||||
|
||||
def switch_lang(self,lang):
|
||||
self.lang = lang
|
||||
self.font_name = self.FONTS.get(lang) or self.DEFAULT_FONT
|
||||
|
||||
class Lang(Observable):
|
||||
observers = []
|
||||
callbacks = []
|
||||
FONTS = {"ko": "fonts/NotoSansKR-Regular.otf"}
|
||||
|
||||
def __init__(self, lang):
|
||||
super(Lang, self).__init__()
|
||||
self.ugettext = None
|
||||
self.font = None
|
||||
self.switch_lang(lang)
|
||||
|
||||
def _(self, text):
|
||||
if text=='':
|
||||
return '' # just for font change
|
||||
return self.ugettext(text)
|
||||
|
||||
def fbind(self, name, func, *args, **kwargs):
|
||||
def fbind(self, name, func, *args):
|
||||
if name == "_":
|
||||
self.observers.append((func, args, kwargs))
|
||||
widget, property, *_ = args[0]
|
||||
self.observers.append((widget, func, args))
|
||||
widget.font_name = self.font_name
|
||||
else:
|
||||
return super(Lang, self).fbind(name, func, *args, **kwargs)
|
||||
return super(Lang, self).fbind(name, func, *args)
|
||||
|
||||
def funbind(self, name, func, *args, **kwargs):
|
||||
def funbind(self, name, func, *args):
|
||||
if name == "_":
|
||||
key = (func, args, kwargs)
|
||||
print("funbind", key in self.observers)
|
||||
widget, *_ = args[0]
|
||||
key = (widget, func, args)
|
||||
if key in self.observers:
|
||||
self.observers.remove(key)
|
||||
else:
|
||||
return super(Lang, self).funbind(name, func, *args, **kwargs)
|
||||
return super(Lang, self).funbind(name, func, *args)
|
||||
|
||||
def add_callback(self,callback_fn: Callable):
|
||||
self.callbacks.append(callback_fn)
|
||||
print("ADDING CB")
|
||||
|
||||
def switch_lang(self, lang):
|
||||
# get the right locales directory, and instantiate a gettext
|
||||
self.lang = lang
|
||||
self.font_name = self.FONTS.get(lang) or DEFAULT_FONT
|
||||
i18n_dir, _ = os.path.split(find_package_resource("katrain/i18n/__init__.py"))
|
||||
locale_dir = os.path.join(i18n_dir, "locales")
|
||||
locales = gettext.translation("katrain", locale_dir, languages=[lang])
|
||||
self.ugettext = locales.gettext
|
||||
|
||||
# update all the kv rules attached to this text
|
||||
for func, args, kwargs in self.observers:
|
||||
for widget, func, args in self.observers:
|
||||
try:
|
||||
func(args[0], None, None)
|
||||
widget.font_name = self.font_name
|
||||
except ReferenceError:
|
||||
pass # proxy no longer exists
|
||||
|
||||
for cb in self.callbacks:
|
||||
try:
|
||||
cb(self)
|
||||
print("CALLING CB")
|
||||
except Exception as e:
|
||||
print(f"Failed callback on language change: {e}",file=sys.stderr)
|
||||
|
||||
|
||||
DEFAULT_LANGUAGE = "en"
|
||||
i18n = Lang(DEFAULT_LANGUAGE)
|
||||
i18n_font = LangFont(DEFAULT_LANGUAGE)
|
||||
|
||||
|
||||
def switch_lang(lang):
|
||||
i18n.switch_lang(lang)
|
||||
i18n_font.switch_lang(lang)
|
||||
+34
-10
@@ -1,6 +1,5 @@
|
||||
#:kivy 1.11.0
|
||||
#:import i18n __main__.i18n
|
||||
#:import i18n_font __main__.i18n_font
|
||||
#:import find_package_resource __main__.find_package_resource
|
||||
|
||||
#:set BUTTON_COLOR [0.23, 0.30, 0.35, 1]
|
||||
@@ -34,7 +33,6 @@
|
||||
#:set NOTES_FONT_SIZE dp(18)
|
||||
|
||||
<Label>:
|
||||
font_name: i18n_font.font_name
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba: RED
|
||||
@@ -42,9 +40,6 @@
|
||||
rectangle: (*self.pos,*self.size)
|
||||
width: 1
|
||||
|
||||
<TextInput>:
|
||||
font_name: i18n_font.font_name
|
||||
|
||||
# mixins
|
||||
<BackgroundMixin>:
|
||||
canvas.before:
|
||||
@@ -91,6 +86,7 @@
|
||||
id: label
|
||||
padding: [root.padding_x,root.padding_y]
|
||||
color: root.text_color
|
||||
font_name: root.font_name
|
||||
font_size: 0.6 * self.height / len(self.text.split('\\n')) if root._font_size is None else root._font_size
|
||||
halign: root.halign
|
||||
text: root.text
|
||||
@@ -390,8 +386,8 @@
|
||||
min_size: min(self.height,self.width)
|
||||
inactive_line_color: WHITE
|
||||
inactive_fill_color: [1,1,1,0]
|
||||
active_line_color: RED
|
||||
active_fill_color: LIGHTGREY
|
||||
active_line_color: [242/255,96/255,34/255,1]
|
||||
active_fill_color: [1,1,1,0]
|
||||
line_width: max(1.1,self.min_size/20)
|
||||
line_color: root.active_line_color if self.active else root.inactive_line_color
|
||||
fill_color: root.active_fill_color if self.active else root.inactive_fill_color
|
||||
@@ -403,16 +399,20 @@
|
||||
pos: root.x + root.width/2 - root.min_size/2, root.y + root.height/2 - root.min_size/2
|
||||
size: root.min_size,root.min_size
|
||||
Color:
|
||||
rgba: root.line_color
|
||||
rgba: root.inactive_line_color
|
||||
Line:
|
||||
circle: root.x + root.width/2, root.y + root.height/2, root.min_size/2 - root.line_width/2
|
||||
width: root.line_width
|
||||
Color:
|
||||
rgba: root.line_color
|
||||
Line:
|
||||
points: root.x + root.width/2 - root.min_size/8, root.y + root.height/2 - root.min_size/6, root.x + root.width/2 - root.min_size/8, root.y + root.height/2 + root.min_size/6
|
||||
width: root.line_width
|
||||
cap: 'square'
|
||||
Line:
|
||||
points: root.x + root.width/2 + root.min_size/8, root.y + root.height/2 - root.min_size/6, root.x + root.width/2 + root.min_size/8, root.y + root.height/2 + root.min_size/6
|
||||
width: root.line_width
|
||||
cap: 'square'
|
||||
|
||||
|
||||
|
||||
@@ -553,6 +553,7 @@
|
||||
id: desc
|
||||
text: root.label if not root.hidden else ''
|
||||
font_size: self.size[1] * 0.7
|
||||
font_name: root.font_name
|
||||
text_size: self.size
|
||||
valign: 'middle'
|
||||
halign: 'center'
|
||||
@@ -561,6 +562,7 @@
|
||||
text: root.text if not root.hidden else ''
|
||||
color: root.color
|
||||
font_size: desc.font_size
|
||||
font_name: root.font_name
|
||||
text_size: self.size
|
||||
valign: 'middle'
|
||||
halign: 'center'
|
||||
@@ -602,6 +604,7 @@
|
||||
width: 1
|
||||
Label:
|
||||
id: label
|
||||
lang_change_tracking: i18n._('')
|
||||
markup: root.markup
|
||||
padding: 5, 5
|
||||
font_size: NOTES_FONT_SIZE
|
||||
@@ -703,7 +706,7 @@
|
||||
size_hint_y_open: 1
|
||||
closed_label: 'closedlabel:info¬es'
|
||||
options: ['info','notes']
|
||||
option_colors: [SCORE_COLOR,WINRATE_COLOR]
|
||||
option_colors: [WHITE,WHITE]
|
||||
option_default_active: [True,False]
|
||||
on_option_state:
|
||||
info.size_hint_y = int(args[1]['info'])+1e-9
|
||||
@@ -745,6 +748,7 @@
|
||||
text: root.text
|
||||
halign: 'center'
|
||||
font_size: root.height / 3
|
||||
font_name: root.font_name
|
||||
color: checkbox.selected_color if checkbox.active else checkbox.unselected_color
|
||||
size_hint_x: None
|
||||
width: self.texture_size[0] + 4
|
||||
@@ -840,6 +844,7 @@
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
font_size: root.font_size
|
||||
font_name: root.font_name
|
||||
color: WHITE
|
||||
Label:
|
||||
text: root.shortcut
|
||||
@@ -847,6 +852,7 @@
|
||||
valign: 'middle'
|
||||
size_hint_x: 1/3
|
||||
font_size: root.font_size
|
||||
font_name: root.font_name
|
||||
color: LIGHTGREY
|
||||
|
||||
|
||||
@@ -860,6 +866,24 @@
|
||||
height: self.parent.item_height or 50
|
||||
size_hint: 1,None
|
||||
|
||||
|
||||
<PlayerSetup@MDBoxLayout>:
|
||||
orientation: 'horizontal'
|
||||
CircleWithText:
|
||||
text: root.player[0]
|
||||
player: root.player
|
||||
Label:
|
||||
text: 'type'
|
||||
Label:
|
||||
text: 'subtype'
|
||||
|
||||
<PlayerSetupBlock@MDBoxLayout>:
|
||||
orientation: 'vertical'
|
||||
PlayerSetup:
|
||||
player: 'Black'
|
||||
PlayerSetup:
|
||||
player: 'White'
|
||||
|
||||
<ContentNavigationDrawer@MDBoxLayout+BackgroundMixin>:
|
||||
katrain: app.gui
|
||||
background_color: BOX_BACKGROUND_COLOR
|
||||
@@ -867,7 +891,7 @@
|
||||
item_height: self.height/20
|
||||
MenuLabel:
|
||||
text: i18n._('menu:playersetup')
|
||||
Label:
|
||||
PlayerSetupBlock:
|
||||
MenuLabel:
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
|
||||
@@ -428,6 +428,7 @@ class AnalysisControls(MDFloatLayout):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.analysis_menu = None
|
||||
i18n.add_callback(lambda _lang: self.build_menu(0))
|
||||
Clock.schedule_once(self.build_menu, 0)
|
||||
|
||||
def build_menu(self, _dt):
|
||||
|
||||
@@ -30,7 +30,7 @@ from katrain.core.utils import i18n
|
||||
#
|
||||
|
||||
# --- new mixins
|
||||
from katrain.gui.style import WHITE
|
||||
from katrain.gui.style import WHITE, DEFAULT_FONT
|
||||
|
||||
|
||||
class BackgroundMixin(Widget):
|
||||
@@ -76,6 +76,7 @@ class SizedButton(LeftButtonBehavior, RectangularRippleBehavior, BasePressedButt
|
||||
padding_x = NumericProperty(6)
|
||||
padding_y = NumericProperty(0)
|
||||
_font_size = NumericProperty(None)
|
||||
font_name = StringProperty(DEFAULT_FONT)
|
||||
|
||||
|
||||
class AutoSizedButton(SizedButton):
|
||||
@@ -113,7 +114,8 @@ class TransparentIconButton(CircularRippleBehavior, Button):
|
||||
icon_size = ListProperty([25, 25])
|
||||
icon = StringProperty("")
|
||||
|
||||
class PauseButton(CircularRippleBehavior,LeftButtonBehavior,Widget):
|
||||
|
||||
class PauseButton(CircularRippleBehavior, LeftButtonBehavior, Widget):
|
||||
active = BooleanProperty(True)
|
||||
active_line_color = ListProperty([0.5, 0.5, 0.8, 1])
|
||||
inactive_line_color = ListProperty([1, 1, 1, 1])
|
||||
@@ -138,6 +140,7 @@ class StatsLabel(MDBoxLayout):
|
||||
label = StringProperty("")
|
||||
color = ListProperty([1, 1, 1, 1])
|
||||
hidden = BooleanProperty(False)
|
||||
font_name = StringProperty(DEFAULT_FONT)
|
||||
|
||||
|
||||
class MyNavigationDrawer(MDNavigationDrawer): # in PR - closes NavDrawer on any outside click
|
||||
@@ -159,6 +162,9 @@ class CircleWithText(Widget):
|
||||
|
||||
# -- new gui elements
|
||||
|
||||
class PlayerSetup(MDBoxLayout):
|
||||
player = OptionProperty("Black", options=["Black", "White"])
|
||||
|
||||
|
||||
class PlayerInfo(MDBoxLayout, BackgroundMixin):
|
||||
captures = NumericProperty(0)
|
||||
@@ -171,6 +177,7 @@ class PlayerInfo(MDBoxLayout, BackgroundMixin):
|
||||
class AnalysisToggle(MDBoxLayout):
|
||||
text = StringProperty("")
|
||||
default_active = BooleanProperty(False)
|
||||
font_name = StringProperty(DEFAULT_FONT)
|
||||
|
||||
def trigger_action(self, *args, **kwargs):
|
||||
return self.checkbox.trigger_action(*args, **kwargs)
|
||||
@@ -185,6 +192,7 @@ class MainMenuItem(RectangularRippleBehavior, LeftButtonBehavior, MDBoxLayout, B
|
||||
icon = StringProperty("")
|
||||
text = StringProperty("")
|
||||
shortcut = StringProperty("")
|
||||
font_name = StringProperty(DEFAULT_FONT)
|
||||
|
||||
def on_left_release(self):
|
||||
self.anim_complete() # kill ripple
|
||||
@@ -308,6 +316,7 @@ class StatsBox(MDBoxLayout, BackgroundMixin):
|
||||
points_lost = NumericProperty(None, allownone=True)
|
||||
player = StringProperty("")
|
||||
|
||||
|
||||
# --- not checked
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ def to_hexcol(kivycol):
|
||||
return "#" + "".join(f"{round(c * 255):02x}" for c in kivycol[:3])
|
||||
|
||||
|
||||
DEFAULT_FONT = "fonts/NotoSans-Regular.ttf"
|
||||
|
||||
# basic color definitions
|
||||
RED = [0.8, 0.1, 0.1, 1]
|
||||
WHITE = [0.95, 0.95, 0.95, 1]
|
||||
|
||||
Binary file not shown.
@@ -6,7 +6,6 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
#. main hamburger menu
|
||||
msgid "menu:playersetup"
|
||||
msgstr "Player Setup"
|
||||
|
||||
Binary file not shown.
@@ -6,7 +6,6 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
msgid "pass-button-text"
|
||||
msgstr "패스"
|
||||
|
||||
@@ -162,8 +161,8 @@ msgstr ""
|
||||
#. TODO
|
||||
msgid "analysis:nextmoves"
|
||||
msgstr ""
|
||||
"Next\n"
|
||||
"Moves"
|
||||
"다음 수\n"
|
||||
"보기"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:policy"
|
||||
@@ -174,9 +173,8 @@ msgstr ""
|
||||
#. TODO
|
||||
msgid "ai-ponder"
|
||||
msgstr ""
|
||||
"This simply indicates the Engine status, going from green (idle) to orange "
|
||||
"(processing queries). It turns red when the engine has crashed or fails to "
|
||||
"start."
|
||||
"이것은 Engine status이에요, going from green (idle) to orange (processing "
|
||||
"queries). It turns red when the engine has crashed or fails to start."
|
||||
|
||||
#. TODO
|
||||
msgid "menu:newgame"
|
||||
@@ -204,7 +202,7 @@ msgstr "Player Setup"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:sweep"
|
||||
msgstr "Fast analysis of all moves"
|
||||
msgstr "Fast analysis of all mㅇves"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:equalize"
|
||||
|
||||
Binary file not shown.
@@ -6,7 +6,6 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
msgid "pass-button-text"
|
||||
msgstr "Pas"
|
||||
|
||||
|
||||
Reference in new issue
Block a user