diff --git a/.github/scripts/build_i18n_messages.py b/.github/scripts/build_i18n_messages.py index 33867e5c..6451b3bb 100644 --- a/.github/scripts/build_i18n_messages.py +++ b/.github/scripts/build_i18n_messages.py @@ -12,9 +12,9 @@ Guardrails: are extracted before translation and restored afterwards, so the interpolation contract stays intact regardless of what the translation provider does with the surrounding text. - - `sk` is skipped by default; override with --languages es,de,fr,it,pt,sk - if you ever want to include it (which will only fill missing keys, - not overwrite the existing 3632). + - `sk` IS translated by default too. Guardrail #1 protects every key + Vaso73 has curated by hand; auto-translation only fills the keys + that are still on the English fallback in sk. Reuses the same translation providers as build_translation_cache.py so 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 -# workflow run cannot accidentally overwrite curated strings. Users can -# still pass --languages ...,sk if they want auto-fill for missing keys. -DEFAULT_LANGUAGES = ("es", "de", "fr", "it", "pt") +# sk IS included in the default. Guardrail #1 (never overwrite a key +# whose target value differs from EN) protects every string Vaso73 has +# already curated by hand — auto-translation only ever touches keys +# 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:" # next-intl / ICU-style placeholders: {name}, {vmid}, {count}, {app_name}. @@ -169,9 +173,9 @@ def build_arg_parser() -> argparse.ArgumentParser: "--languages", default=",".join(DEFAULT_LANGUAGES), help=( - "Comma-separated target locales. Default excludes sk " - "(human-curated by Vaso73). Adding sk here only fills " - "keys that are still identical to the English fallback." + "Comma-separated target locales. Includes sk by default; " + "guardrail #1 never overwrites keys whose sk value differs " + "from EN, so Vaso73's curated translations are safe." ), ) parser.add_argument( diff --git a/.github/scripts/build_translation_cache.py b/.github/scripts/build_translation_cache.py index e25492ea..dddc9380 100644 --- a/.github/scripts/build_translation_cache.py +++ b/.github/scripts/build_translation_cache.py @@ -28,7 +28,7 @@ from urllib.parse import quote 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:" TRANSLATE_CALL_RE = re.compile( r"""translate\s+(?P["'])(?P(?:\\.|(?! (?P=quote) ).)*?)(?P=quote)""", diff --git a/.github/workflows/build-i18n-messages.yml b/.github/workflows/build-i18n-messages.yml index ba57d70d..27dda6c9 100644 --- a/.github/workflows/build-i18n-messages.yml +++ b/.github/workflows/build-i18n-messages.yml @@ -10,12 +10,11 @@ name: Build i18n messages # # Guardrails baked into build_i18n_messages.py: # - 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. -# - `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: # - push to develop touching AppImage/messages/en/common.json @@ -35,8 +34,8 @@ on: type: boolean default: false languages: - description: 'Comma-separated locales. Default: es,de,fr,it,pt (sk skipped).' - default: 'es,de,fr,it,pt' + description: 'Comma-separated locales. Default: es,de,fr,it,pt,sk,sv (guardrail protects Vaso73 sk).' + default: 'es,de,fr,it,pt,sk,sv' # 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 diff --git a/AppImage/lib/i18n/languages.ts b/AppImage/lib/i18n/languages.ts index a38822c3..79a4908a 100644 --- a/AppImage/lib/i18n/languages.ts +++ b/AppImage/lib/i18n/languages.ts @@ -1,7 +1,7 @@ export const LANGUAGE_STORAGE_KEY = "proxmenux-ui-language" 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" @@ -20,6 +20,7 @@ export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [ { code: "de", englishName: "German", nativeName: "Deutsch", status: "needs-translation" }, { code: "it", englishName: "Italian", nativeName: "Italiano", 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 { diff --git a/AppImage/messages/sv/common.json b/AppImage/messages/sv/common.json new file mode 100644 index 00000000..1d57bb1b --- /dev/null +++ b/AppImage/messages/sv/common.json @@ -0,0 +1,3 @@ +{ + "_meta": "Community translation target. Copy keys from ../en/common.json and translate the values. Placeholders like {vmid} must stay unchanged." +}