feat: backend i18n — serve translated component metadata via Accept-Language - #12517
Merged
Conversation
- Add GP REST API client with GP-HMAC authentication (scripts/gp/gp_client.py) - Add upload/download scripts for syncing strings with GP - Set up i18next + react-i18next with 7 language support (en, fr, ja, es, de, pt, zh-Hans) - Add 48 UI strings in flat dot notation to en.json (from alerts_constants) - Add GitHub Actions for automated upload on en.json changes and daily translation download
- Fix quote style, import ordering, docstring format - Use Path instead of os.makedirs/open/os.path.join - Add missing timeouts to requests calls - Move noqa comments to correct lines for S501
- Replace all hardcoded user-facing strings with t() calls across 80+ components, pages, modals, and utilities - Add 326 translation keys to en.json covering errors, alerts, dialogs, chat, flow, settings, store, table, output, nav, auth, and more - Add translated locale files for fr, es, de, pt, ja, zh-Hans (downloaded from Globalization Pipeline) - Migrate alerts_constants.tsx and constants.ts string usages to react-i18next - Support non-React files (stores, utils) via i18n.t() direct calls
- Add 56 new translation keys for sidebar categories, nav items, labels, buttons, and empty states - Convert SIDEBAR_CATEGORIES display_names to i18n key references in styleUtils.ts - Update 13 sidebar components to use t() for all user-facing strings - Refresh all 6 locale files from GP (382 total keys) - Add BACKEND_STRINGS_STRATEGY.md documenting plan for component display_name i18n
- Add global react-i18next mock in jest.setup.js using en.json lookups so t(key) returns English strings instead of raw keys in test environment - Fix sidebarSegmentedNav tests: update NAV_ITEMS expectations to use i18n keys, and use en.json lookups for tooltip/accessibility label assertions
Cherry-picked frontend-only changes from feat/gp-backend-i18n (6ab2155, 3e274a8): - Add LanguageSelector component with dropdown to switch UI language - Wire LanguageSelector into AccountMenu header - Persist language preference to localStorage in i18n.ts - Send Accept-Language header via useCustomApiHeaders (reactive via useTranslation) No backend files included.
Downloads frontend translations from Globalization Pipeline after create-nightly-tag and before frontend tests run, ensuring tests always validate the latest translated locale files. - Frontend tests (Linux/Windows) now depend on download-gp-bundle - Backend unit tests are unaffected (no frontend locale dependency) - GP failure blocks release-nightly-build (same severity as linux tests)
Remove BACKEND_STRINGS_STRATEGY.md (internal planning doc), test_auth.py (GP auth debugging script), and en.json (dev-time string snapshot). Also add venv/ to .gitignore to prevent accidental commits of the local virtualenv.
Category headers use truncate but had no tooltip, making long translated names (e.g. French) unreadable. Wrap the label span with ShadTooltip matching the pattern used by sidebar draggable items.
…n button for consistency
- FBT001: make dry_run keyword-only in bake_note_keys._bake_file - S112: add S112 to noqa comments in extract_backend_strings.py - PLW2901: rename shadowed loop variable in i18n.translate_note_nodes
…ollection The top-level `from langflow.utils.i18n_keys import ...` caused an ImportError in CI where the GP test job runs without langflow installed. Move the imports inside collect_strings() so the module is importable without langflow — all tests mock collect_strings anyway.
…ps_deactivated_modules The test calls collect_strings() directly, which now lazy-imports langflow.utils.i18n_keys. Patch a minimal fake module into sys.modules so the test runs without langflow installed. Also fix the key assertion to match the lowercased output of normalize_component_key.
…edgeBaseUploadModal The i18n commit (bd070ca) accidentally dropped MODAL_HEIGHT_DEFAULT, MODAL_HEIGHT_WITH_ADVANCED, and VALIDATION_ERROR_LINE_HEIGHT from the constants import when refactoring STEP_TITLES/STEP_DESCRIPTIONS, causing a ReferenceError at runtime and failing all 39 Jest tests.
…nsQuery
- Mock shadTooltipComponent to render children only — avoids needing
TooltipProvider in sidebar unit tests
- Mock useGetNoteTranslationsQuery to return empty data — avoids needing
QueryClientProvider in NoteNode unit tests
- Fix t() interpolation mock to resolve {{count}} in KnowledgeBasesTab tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…in syncNodeTranslations Only sync field-level translations (template inputs and outputs). Node titles and descriptions are instance-level identity — user and template renames must not be overwritten by canonical registry values.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Backend component i18n (original scope)
src/backend/base/langflow/locales/with 4,748 flat keys across 359 components (Tier 1: component display_name/description; Tier 2: input/output field display_names)set_localeinmain.pyparses the header once per request and setsrequest.state.locale;/api/v1/allcallstranslate_component_dict()for non-English locales, leaving the English fast path untouchedextract_backend_strings.py(with--checkCI flag),upload_backend_strings.py,download_backend_translations.pyusing a separatelangflow-backendGP bundlegp-backend-check.yml(PR validation + auto-commit on non-fork PRs),gp-backend-upload.yml(extract → upload onrelease-*branches)useCustomApiHeaderssendsAccept-Language; language change clearsuseTypesStoreand invalidates["useGetTypes"]so the sidebar refreshes without a page reloadsyncNodeTranslations()inflowStorepatches all canvas nodes whenever the types catalog is refreshedStarter flow metadata i18n (new)
extract_backend_strings.pynow auto-discovers allinitial_setup/starter_projects/*.jsonfiles and emitsstarter_flows.{safe_key}.name/starter_flows.{safe_key}.descriptionkeys; no manual work needed when new starter flows are addedtranslate_starter_flows()— new function inutils/i18n.pymirroringtranslate_component_dict(); derives a stablename_keyslug from the English name and attaches it to eachFlowReadFlowRead.name_key— stable locale-independent slug exposed on the response model so the frontend can match flows by identity regardless of the active languageread_basic_examples()refactor — acceptsRequest, caches rawflow_readslist (not compressed response), translates per-request via locale from middleware; refetch triggered on language change viai18n.languagein React Query keyTemplates modal & empty page i18n (new)
emptyPageandemptyFolderArchitecture
Test plan
Accept-Language: xx) falls back to Englishpython scripts/gp/extract_backend_strings.py --check— exits 0 (en.json in sync)starter_projects/*.json→ re-run extract → new keys appear automaticallyReplaces #12258.