mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-08-09 09:16:20 +00:00
feat(i18n): add Swedish support + include Slovak in auto-fill defaults
Two related changes to the translation infrastructure: 1. Add Swedish (sv) as a supported locale in both the CLI and Monitor translation systems. Inspired by PR #121, which arrived before the current auto-generated cache layout existed. 2. Include Slovak (sk) in the default auto-fill target set. Guardrail #1 in build_i18n_messages.py never overwrites a key whose target value differs from EN, so Vaso73's curated Slovak strings stay intact — auto-translation only fills keys that are still on the English fallback. Trade-off accepted: sk users see decent machine translation for new keys immediately instead of raw English while human curation catches up, and Vaso73 keeps full ownership of the wording via follow-up PRs. Changes: - AppImage/lib/i18n/languages.ts: add "sv" to LanguageCode + register in SUPPORTED_LANGUAGES. - AppImage/messages/sv/common.json: stub — will be filled by the i18n workflow on the local bootstrap. - .github/scripts/build_translation_cache.py: add "sv" to DEFAULT_LANGUAGES. - .github/scripts/build_i18n_messages.py: add "sk" and "sv" to DEFAULT_LANGUAGES; update comments to explain the sk decision. - .github/workflows/build-i18n-messages.yml: default input includes sk + sv; comments updated to match.
This commit is contained in:
@@ -12,9 +12,9 @@ Guardrails:
|
|||||||
are extracted before translation and restored afterwards, so the
|
are extracted before translation and restored afterwards, so the
|
||||||
interpolation contract stays intact regardless of what the
|
interpolation contract stays intact regardless of what the
|
||||||
translation provider does with the surrounding text.
|
translation provider does with the surrounding text.
|
||||||
- `sk` is skipped by default; override with --languages es,de,fr,it,pt,sk
|
- `sk` IS translated by default too. Guardrail #1 protects every key
|
||||||
if you ever want to include it (which will only fill missing keys,
|
Vaso73 has curated by hand; auto-translation only fills the keys
|
||||||
not overwrite the existing 3632).
|
that are still on the English fallback in sk.
|
||||||
|
|
||||||
Reuses the same translation providers as build_translation_cache.py so
|
Reuses the same translation providers as build_translation_cache.py so
|
||||||
the CI environment (googletrans pinning, AppImage provider) stays
|
the CI environment (googletrans pinning, AppImage provider) stays
|
||||||
@@ -40,10 +40,14 @@ from build_translation_cache import ( # noqa: E402
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# sk is human-curated (Vaso73); default set excludes it so a naive
|
# sk IS included in the default. Guardrail #1 (never overwrite a key
|
||||||
# workflow run cannot accidentally overwrite curated strings. Users can
|
# whose target value differs from EN) protects every string Vaso73 has
|
||||||
# still pass --languages ...,sk if they want auto-fill for missing keys.
|
# already curated by hand — auto-translation only ever touches keys
|
||||||
DEFAULT_LANGUAGES = ("es", "de", "fr", "it", "pt")
|
# that are still on the English fallback in sk. Trade-off accepted:
|
||||||
|
# users on sk see a decent auto-translation for new keys instead of raw
|
||||||
|
# English while the human maintainer catches up, and Vaso73 keeps full
|
||||||
|
# ownership of the wording via follow-up PRs.
|
||||||
|
DEFAULT_LANGUAGES = ("es", "de", "fr", "it", "pt", "sk", "sv")
|
||||||
DEFAULT_CONTEXT = "Context: Technical UI text for a Proxmox management dashboard. Translate:"
|
DEFAULT_CONTEXT = "Context: Technical UI text for a Proxmox management dashboard. Translate:"
|
||||||
|
|
||||||
# next-intl / ICU-style placeholders: {name}, {vmid}, {count}, {app_name}.
|
# next-intl / ICU-style placeholders: {name}, {vmid}, {count}, {app_name}.
|
||||||
@@ -169,9 +173,9 @@ def build_arg_parser() -> argparse.ArgumentParser:
|
|||||||
"--languages",
|
"--languages",
|
||||||
default=",".join(DEFAULT_LANGUAGES),
|
default=",".join(DEFAULT_LANGUAGES),
|
||||||
help=(
|
help=(
|
||||||
"Comma-separated target locales. Default excludes sk "
|
"Comma-separated target locales. Includes sk by default; "
|
||||||
"(human-curated by Vaso73). Adding sk here only fills "
|
"guardrail #1 never overwrites keys whose sk value differs "
|
||||||
"keys that are still identical to the English fallback."
|
"from EN, so Vaso73's curated translations are safe."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from urllib.parse import quote
|
|||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_LANGUAGES = ("es", "fr", "de", "it", "pt", "sk")
|
DEFAULT_LANGUAGES = ("es", "fr", "de", "it", "pt", "sk", "sv")
|
||||||
DEFAULT_CONTEXT = "Context: Technical message for Proxmox and IT. Translate:"
|
DEFAULT_CONTEXT = "Context: Technical message for Proxmox and IT. Translate:"
|
||||||
TRANSLATE_CALL_RE = re.compile(
|
TRANSLATE_CALL_RE = re.compile(
|
||||||
r"""translate\s+(?P<quote>["'])(?P<text>(?:\\.|(?! (?P=quote) ).)*?)(?P=quote)""",
|
r"""translate\s+(?P<quote>["'])(?P<text>(?:\\.|(?! (?P=quote) ).)*?)(?P=quote)""",
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ name: Build i18n messages
|
|||||||
#
|
#
|
||||||
# Guardrails baked into build_i18n_messages.py:
|
# Guardrails baked into build_i18n_messages.py:
|
||||||
# - Never overwrites a key whose target value differs from EN (i.e.
|
# - Never overwrites a key whose target value differs from EN (i.e.
|
||||||
# already translated by a human).
|
# already translated by a human). This is what makes it safe to
|
||||||
|
# include sk in the default set: Vaso73's curated strings are
|
||||||
|
# protected end-to-end; auto only fills keys still on the EN
|
||||||
|
# fallback.
|
||||||
# - `{placeholder}` tokens are protected end-to-end.
|
# - `{placeholder}` tokens are protected end-to-end.
|
||||||
# - `sk` is excluded from the default list — Vaso73's locale is
|
|
||||||
# human-curated and full. Add it back via workflow_dispatch inputs
|
|
||||||
# if you ever want auto-fill for the ~200 keys added post his last
|
|
||||||
# PR (only missing keys will be touched; existing ones are safe).
|
|
||||||
#
|
#
|
||||||
# Triggers:
|
# Triggers:
|
||||||
# - push to develop touching AppImage/messages/en/common.json
|
# - push to develop touching AppImage/messages/en/common.json
|
||||||
@@ -35,8 +34,8 @@ on:
|
|||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
languages:
|
languages:
|
||||||
description: 'Comma-separated locales. Default: es,de,fr,it,pt (sk skipped).'
|
description: 'Comma-separated locales. Default: es,de,fr,it,pt,sk,sv (guardrail protects Vaso73 sk).'
|
||||||
default: 'es,de,fr,it,pt'
|
default: 'es,de,fr,it,pt,sk,sv'
|
||||||
|
|
||||||
# Prevent two runs from racing on the same branch and fighting over the
|
# Prevent two runs from racing on the same branch and fighting over the
|
||||||
# auto-commit. cancel-in-progress:false because a full first-run may take
|
# auto-commit. cancel-in-progress:false because a full first-run may take
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export const LANGUAGE_STORAGE_KEY = "proxmenux-ui-language"
|
export const LANGUAGE_STORAGE_KEY = "proxmenux-ui-language"
|
||||||
export const DEFAULT_LANGUAGE = "en"
|
export const DEFAULT_LANGUAGE = "en"
|
||||||
|
|
||||||
export type LanguageCode = "en" | "es" | "fr" | "de" | "it" | "pt" | "sk"
|
export type LanguageCode = "en" | "es" | "fr" | "de" | "it" | "pt" | "sk" | "sv"
|
||||||
|
|
||||||
export type LanguageStatus = "complete" | "partial" | "needs-translation"
|
export type LanguageStatus = "complete" | "partial" | "needs-translation"
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [
|
|||||||
{ code: "de", englishName: "German", nativeName: "Deutsch", status: "needs-translation" },
|
{ code: "de", englishName: "German", nativeName: "Deutsch", status: "needs-translation" },
|
||||||
{ code: "it", englishName: "Italian", nativeName: "Italiano", status: "needs-translation" },
|
{ code: "it", englishName: "Italian", nativeName: "Italiano", status: "needs-translation" },
|
||||||
{ code: "pt", englishName: "Portuguese", nativeName: "Português", status: "needs-translation" },
|
{ code: "pt", englishName: "Portuguese", nativeName: "Português", status: "needs-translation" },
|
||||||
|
{ code: "sv", englishName: "Swedish", nativeName: "Svenska", status: "needs-translation" },
|
||||||
]
|
]
|
||||||
|
|
||||||
export function isSupportedLanguage(value: string | null | undefined): value is LanguageCode {
|
export function isSupportedLanguage(value: string | null | undefined): value is LanguageCode {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"_meta": "Community translation target. Copy keys from ../en/common.json and translate the values. Placeholders like {vmid} must stay unchanged."
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user