fix(i18n): address Greptile review feedback (LC_ALL precedence, string dict validation, PyInstaller spec, CLI --language flag, system prompt injection)

This commit is contained in:
tmguat56 2026-08-14 17:58:12 +07:00
parent 8fd2334e11
commit 4264af7a9e
5 changed files with 43 additions and 5 deletions

View file

@ -36,6 +36,10 @@ for asset in viewer_static.rglob('*'):
rel_path = asset.relative_to(project_root)
datas.append((str(asset), str(rel_path.parent)))
for json_locale in strix_root.rglob('locales/*.json'):
rel_path = json_locale.relative_to(project_root)
datas.append((str(json_locale), str(rel_path.parent)))
datas += collect_data_files('tiktoken')
datas += collect_data_files('tiktoken_ext')
@ -112,6 +116,7 @@ hiddenimports = [
# Strix modules
'strix',
'strix.i18n',
'strix.interface',
'strix.interface.main',
'strix.interface.cli',

View file

@ -1,4 +1,9 @@
You are an advanced AI application security validation agent. Your purpose is to perform authorized security verification, reproduce and validate weaknesses on in-scope assets, and help remediate real security issues.
{% if language_directive %}
<language_directive>
{{ language_directive }}
</language_directive>
{% endif %}
You follow all instructions and rules provided to you exactly as written in the system prompt at all times.
{% if is_root %}
<root_agent_directive>

View file

@ -147,6 +147,10 @@ class ViewerSettings(BaseSettings):
class Settings(BaseSettings):
model_config = _BASE_CONFIG
language: str = Field(
default="en",
validation_alias=AliasChoices("STRIX_LANGUAGE", "language"),
)
llm: LlmSettings = Field(default_factory=LlmSettings)
dedupe: DedupeSettings = Field(default_factory=DedupeSettings)
runtime: RuntimeSettings = Field(default_factory=RuntimeSettings)

View file

@ -45,11 +45,13 @@ def get_language() -> str:
def _detect_language() -> str:
"""Detect language via STRIX_LANGUAGE, config file, or system LANG."""
"""Detect language via STRIX_LANGUAGE, config file, or system LANG/LC_ALL."""
# 1. Environment Variable STRIX_LANGUAGE
env_lang = os.getenv("STRIX_LANGUAGE")
if env_lang:
return _normalize_lang(env_lang)
# 2. Config File ~/.strix/cli-config.json
try:
cfg_path = Path.home() / ".strix" / "cli-config.json"
if cfg_path.exists():
@ -60,7 +62,8 @@ def _detect_language() -> str:
except Exception:
pass
sys_lang = os.getenv("LANG") or os.getenv("LC_ALL")
# 3. System Locale (LC_ALL takes precedence over LANG)
sys_lang = os.getenv("LC_ALL") or os.getenv("LANG")
if sys_lang:
return _normalize_lang(sys_lang)
@ -68,24 +71,32 @@ def _detect_language() -> str:
def _load_locale(lang: str) -> Dict[str, str]:
"""Load locale JSON file with thread-safe caching and user overrides."""
"""Load locale JSON file with thread-safe caching, type validation, and user overrides."""
with _locales_lock:
if lang in _locales_cache:
return _locales_cache[lang]
translations: Dict[str, str] = {}
def _safe_merge(source_data: Any) -> None:
if isinstance(source_data, dict):
for k, v in source_data.items():
if isinstance(k, str) and isinstance(v, str):
translations[k] = v
# Built-in locale
builtin_path = Path(__file__).parent / "locales" / f"{lang}.json"
if builtin_path.exists():
try:
translations.update(json.loads(builtin_path.read_text(encoding="utf-8")))
_safe_merge(json.loads(builtin_path.read_text(encoding="utf-8")))
except Exception:
pass
# User override locale (~/.strix/locales/{lang}.json)
user_path = Path.home() / ".strix" / "locales" / f"{lang}.json"
if user_path.exists():
try:
translations.update(json.loads(user_path.read_text(encoding="utf-8")))
_safe_merge(json.loads(user_path.read_text(encoding="utf-8")))
except Exception:
pass

View file

@ -50,6 +50,13 @@ def _positive_int(value: str) -> int:
def parse_arguments() -> argparse.Namespace:
# Pre-resolve language before argparse if set in sys.argv
for idx, arg in enumerate(sys.argv[:-1]):
if arg in ("--language", "-l") and idx + 1 < len(sys.argv):
from strix.i18n import set_language
set_language(sys.argv[idx + 1])
break
parser = argparse.ArgumentParser(
description="Strix Multi-Agent Cybersecurity Penetration Testing Tool",
formatter_class=argparse.RawDescriptionHelpFormatter,
@ -108,6 +115,12 @@ Examples:
help="Update strix to the latest version and exit. Self-updates the "
"standalone binary install; for pip/pipx/uv installs, prints the "
"matching upgrade command instead.",
parser.add_argument(
"--language",
"-l",
type=str,
default=None,
help="Language preference for CLI messages and audit reports (e.g. en, es, id)",
)
parser.add_argument(