@vtex/faststore-plugin-buyer-portal 2.0.13 → 2.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/cms/b2b/components/.gitkeep +0 -0
  3. package/cms/b2b/pages/cms_content_type__i18n.jsonc +36 -0
  4. package/cypress/integration/localization.test.ts +482 -0
  5. package/cypress/support/commands.ts +8 -0
  6. package/docs/i18n/i18n-messages-format.md +391 -0
  7. package/docs/i18n/locales.json +701 -0
  8. package/docs/i18n/migration-inventory.md +959 -0
  9. package/package.json +3 -3
  10. package/specs/custom-localization-system.md +711 -0
  11. package/specs/multi-locale-e2e-validation.md +277 -0
  12. package/src/__mocks__/discovery.config.ts +12 -0
  13. package/src/features/accounting-fields/components/AccountingConfirmDelete/AccountingConfirmDelete.tsx +14 -4
  14. package/src/features/accounting-fields/components/AccountingFieldConfirmEdit/AccountingFieldConfirmEdit.tsx +11 -6
  15. package/src/features/accounting-fields/components/AccountingFieldDropdown/AccountingFieldDropdown.tsx +5 -3
  16. package/src/features/accounting-fields/components/AccountingFieldForm/AccountingFieldForm.tsx +33 -23
  17. package/src/features/accounting-fields/components/AccountingValueConfirmEdit/AccountingValueConfirmEdit.tsx +10 -6
  18. package/src/features/accounting-fields/components/AccountingValueDropdown/AccountingValueDropdown.tsx +19 -9
  19. package/src/features/accounting-fields/components/AccountingValueForm/AccountingValueForm.tsx +21 -10
  20. package/src/features/accounting-fields/components/CreateAccountingFieldDrawer/CreateAccountingFieldDrawer.tsx +11 -8
  21. package/src/features/accounting-fields/components/CreateAccountingValueDrawer/CreateAccountingValueDrawer.tsx +18 -7
  22. package/src/features/accounting-fields/components/DeleteAccountingFieldDrawer/DeleteAccountingFieldDrawer.tsx +14 -12
  23. package/src/features/accounting-fields/components/DeleteAccountingValueDrawer/DeleteAccountingValueDrawer.tsx +20 -10
  24. package/src/features/accounting-fields/components/EditAccountingFieldDrawer/EditAccountingFieldDrawer.tsx +5 -3
  25. package/src/features/accounting-fields/components/EditAccountingValueDrawer/EditAccountingValueDrawer.tsx +13 -6
  26. package/src/features/accounting-fields/components/RemoveValueFromUnitDrawer/RemoveValueFromUnitDrawer.tsx +19 -8
  27. package/src/features/accounting-fields/layouts/AccountingFieldLayout/AccountingFieldLayout.tsx +11 -9
  28. package/src/features/addresses/components/AddRecipientsDrawer/AddRecipientsDrawer.tsx +13 -7
  29. package/src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx +22 -20
  30. package/src/features/addresses/components/AddressForm/AddressForm.tsx +33 -22
  31. package/src/features/addresses/components/AddressLine/AddressLine.tsx +29 -25
  32. package/src/features/addresses/components/AddressLocationsList/AddressLocationsList.tsx +15 -6
  33. package/src/features/addresses/components/AddressRecipientsList/AddressRecipientsList.tsx +9 -4
  34. package/src/features/addresses/components/AddressesCard/AddressesCard.tsx +8 -5
  35. package/src/features/addresses/components/CreateAddressDrawer/CreateAddressDrawer.tsx +27 -14
  36. package/src/features/addresses/components/CreateAddressSettingsDrawer/CreateAddressSettingsDrawer.tsx +26 -21
  37. package/src/features/addresses/components/DeleteAddressDrawer/DeleteAddressDrawer.tsx +20 -16
  38. package/src/features/addresses/components/DeleteAddressLocationDrawer/DeleteAddressLocationDrawer.tsx +26 -14
  39. package/src/features/addresses/components/DeleteRecipientAddressDrawer/DeleteRecipientAddressDrawer.tsx +20 -17
  40. package/src/features/addresses/components/EditAddressDrawer/EditAddressDrawer.tsx +12 -6
  41. package/src/features/addresses/components/EditAddressLocationDrawer/EditAddressLocationDrawer.tsx +24 -17
  42. package/src/features/addresses/components/EditRecipientAddressDrawer/EditRecipientAddressDrawer.tsx +17 -15
  43. package/src/features/addresses/components/LocationForm/LocationField/LocationField.tsx +8 -5
  44. package/src/features/addresses/components/LocationForm/LocationForm.tsx +9 -3
  45. package/src/features/addresses/components/LocationsDrawer/LocationsDrawer.tsx +15 -9
  46. package/src/features/addresses/components/RecipientsForm/RecipientItem/RecipientItem.tsx +55 -46
  47. package/src/features/addresses/components/RecipientsForm/RecipientsForm.tsx +4 -1
  48. package/src/features/addresses/components/RemoveAddressDrawer/RemoveAddressDrawer.tsx +21 -14
  49. package/src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx +16 -9
  50. package/src/features/addresses/layouts/AddressesLayout/AddressesLayout.tsx +11 -8
  51. package/src/features/b2b-agent/layouts/B2BAgentLayout/B2BAgentLayout.tsx +3 -1
  52. package/src/features/budgets/components/BudgetAddForm/BudgetAddForm.tsx +14 -12
  53. package/src/features/budgets/components/BudgetAddSuccess/BudgetAddSuccess.tsx +16 -14
  54. package/src/features/budgets/components/BudgetAllocationsSelection/BudgetAllocationsSelection.tsx +8 -5
  55. package/src/features/budgets/components/BudgetAllocationsTable/BudgetAllocationsTable.tsx +9 -6
  56. package/src/features/budgets/components/BudgetDeleteDrawer/BudgetDeleteDrawer.tsx +23 -17
  57. package/src/features/budgets/components/BudgetEditNotificationDrawer/BudgetEditNotificationDrawer.tsx +13 -6
  58. package/src/features/budgets/components/BudgetNotificationForm/BudgetNotificationForm.tsx +31 -24
  59. package/src/features/budgets/components/BudgetNotificationsInfo/BudgetNotificationsInfo.tsx +15 -9
  60. package/src/features/budgets/components/BudgetRemainingBalance/BudgetRemainingBalance.tsx +6 -2
  61. package/src/features/budgets/components/BudgetSettingsInfo/BudgetSettingsInfo.tsx +27 -10
  62. package/src/features/budgets/components/BudgetUsersTable/BudgetUsersTable.tsx +14 -7
  63. package/src/features/budgets/components/BudgetsTable/BudgetsTable.tsx +11 -8
  64. package/src/features/budgets/components/CreateBudgetAllocationDrawer/CreateBudgetAllocationDrawer.tsx +8 -5
  65. package/src/features/budgets/components/CreateBudgetDrawer/CreateBudgetDrawer.tsx +31 -18
  66. package/src/features/budgets/components/DeleteBudgetAllocationDrawer/DeleteBudgetAllocationDrawer.tsx +17 -12
  67. package/src/features/budgets/components/EditBudgetDrawer/EditBudgetDrawer.tsx +14 -8
  68. package/src/features/budgets/components/EmptyState.tsx/EmptyState.tsx +4 -1
  69. package/src/features/budgets/layouts/BudgetsDetailsLayout/BudgetsDetailsLayout.tsx +7 -5
  70. package/src/features/budgets/layouts/BudgetsLayout/BudgetsLayout.tsx +5 -3
  71. package/src/features/budgets/messages/budgetNotifications.ts +5 -5
  72. package/src/features/budgets/utils/handleBudgetError.tsx +5 -8
  73. package/src/features/budgets/utils/handleBudgetError.types.ts +3 -0
  74. package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingFieldCriteriaSelector.tsx +5 -3
  75. package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingValueCriteriaSelector.tsx +20 -9
  76. package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx +8 -5
  77. package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +49 -33
  78. package/src/features/buying-policies/components/BudgetCriteriaSelector/BudgetCriteriaSelector.tsx +8 -2
  79. package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/BuyingPolicyDropdownMenu.tsx +5 -3
  80. package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/DeleteBuyingPolicyDrawer.tsx +28 -24
  81. package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/UpdateBuyingPolicyDrawer.tsx +10 -7
  82. package/src/features/buying-policies/layouts/BuyingPoliciesLayout/BuyingPoliciesLayout.tsx +11 -4
  83. package/src/features/buying-policies/layouts/BuyingPolicyDetailsLayout/BuyingPolicyDetailsLayout.tsx +26 -9
  84. package/src/features/buying-policies/utils/accountingFieldCriteriaHelpers.ts +2 -2
  85. package/src/features/buying-policies/utils/buyingPoliciesWorkflowTypes.ts +3 -3
  86. package/src/features/buying-policies/utils/orderFieldsCriteriaOptions.ts +8 -8
  87. package/src/features/buying-policies/utils/spendingLimitsCriteriaOptions.ts +6 -6
  88. package/src/features/contracts/components/ContractsCard/ContractsCard.tsx +7 -5
  89. package/src/features/contracts/layouts/ContractsLayout/ContractsLayout.tsx +9 -4
  90. package/src/features/credit-cards/components/CreateCreditCardDrawer/CreateCreditCardDrawer.tsx +17 -11
  91. package/src/features/credit-cards/components/CreditCardDropdownMenu/CreditCardDropdownMenu.tsx +17 -11
  92. package/src/features/credit-cards/components/CreditCardForm/CreditCardForm.tsx +8 -5
  93. package/src/features/credit-cards/components/CreditCardSettingsDrawer/CreditCardSettingsDrawer.tsx +10 -8
  94. package/src/features/credit-cards/components/DeleteCreditCardDrawer/DeleteCreditCardDrawer.tsx +19 -14
  95. package/src/features/credit-cards/components/EditCreditCardDrawer/EditCreditCardDrawer.tsx +14 -13
  96. package/src/features/credit-cards/components/RemoveCreditCardDrawer/RemoveCreditCardDrawer.tsx +18 -15
  97. package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +10 -4
  98. package/src/features/order-entry/layouts/OrderEntryLayout.tsx +3 -1
  99. package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +11 -9
  100. package/src/features/org-units/components/AuthSetupDrawer/AuthSetupDrawer.tsx +28 -16
  101. package/src/features/org-units/components/CreateOrgUnitDrawer/CreateOrgUnitDrawer.tsx +18 -12
  102. package/src/features/org-units/components/DeleteOrgUnitDrawer/DeleteOrgUnitDrawer.tsx +28 -29
  103. package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumbLink.tsx +4 -4
  104. package/src/features/org-units/components/OrgUnitDetailsDropdownMenu/OrgUnitDetailsDropdownMenu.tsx +4 -2
  105. package/src/features/org-units/components/OrgUnitDetailsNavbar/OrgUnitDetailsNavbar.tsx +23 -5
  106. package/src/features/org-units/components/OrgUnitDetailsNavbar/org-unit-details-navbar.scss +18 -2
  107. package/src/features/org-units/components/OrgUnitsDropdownMenu/OrgUnitsDropdownMenu.tsx +6 -4
  108. package/src/features/org-units/components/OrgUnitsHierarchyTree/OrgUnitsHierarchyTree.tsx +9 -6
  109. package/src/features/org-units/components/OrganizationalUnitsCard/OrganizationalUnitsCard.tsx +15 -7
  110. package/src/features/org-units/components/UpdateOrgUnitDrawer/UpdateOrgUnitDrawer.tsx +15 -9
  111. package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +27 -26
  112. package/src/features/org-units/layouts/OrgUnitsLayout/OrgUnitsLayout.tsx +8 -3
  113. package/src/features/payment-methods/components/AddPaymentMethodsDrawer/AddPaymentMethodsDrawer.tsx +29 -18
  114. package/src/features/payment-methods/components/PaymentMethodSettingsDrawer/PaymentMethodSettingsDrawer.tsx +13 -9
  115. package/src/features/payment-methods/components/RemoveMethodButton/RemoveMethodButton.tsx +5 -2
  116. package/src/features/payment-methods/components/RemovePaymentMethodsDrawer/RemovePaymentMethodsDrawer.tsx +10 -7
  117. package/src/features/payment-methods/hooks/useRemovePaymentMethodSubmit.ts +6 -4
  118. package/src/features/payment-methods/layouts/PaymentMethodsLayout/PaymentMethodsLayout.tsx +21 -15
  119. package/src/features/product-assortment/components/ProductAssortmentTable/ProductAssortmentTable.tsx +11 -7
  120. package/src/features/product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx +9 -6
  121. package/src/features/profile/components/ProfileCard/ProfileCard.tsx +8 -5
  122. package/src/features/profile/components/ProfileSummary/ProfileSummary.tsx +13 -6
  123. package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +16 -6
  124. package/src/features/roles/layout/RoleDetailsLayout/RoleDetailsLayout.tsx +4 -2
  125. package/src/features/roles/layout/RolesLayout/RolesLayout.tsx +5 -3
  126. package/src/features/shared/components/BasicCard/BasicCard.tsx +6 -4
  127. package/src/features/shared/components/BasicCard/BasicCardLine.tsx +5 -4
  128. package/src/features/shared/components/CustomerSwitch/CustomerSwitchDrawer.tsx +10 -2
  129. package/src/features/shared/components/CustomerSwitch/CustomerSwitchSearch.tsx +4 -1
  130. package/src/features/shared/components/DropdownFilter/DropdownFilter.tsx +11 -7
  131. package/src/features/shared/components/Error/Error.tsx +13 -6
  132. package/src/features/shared/components/HeaderInside/HeaderInside.tsx +5 -2
  133. package/src/features/shared/components/InternalSearch/InternalSearch.tsx +4 -1
  134. package/src/features/shared/components/InternalTopbar/InternalTopbar.tsx +7 -5
  135. package/src/features/shared/components/MainLinksDropdownMenu/MainLinksDropdownMenu.tsx +23 -8
  136. package/src/features/shared/components/OrgUnitInputSearch/OrgUnitInputSearch.tsx +7 -2
  137. package/src/features/shared/components/Pagination/Pagination.tsx +6 -2
  138. package/src/features/shared/components/Paginator/Counter.tsx +11 -5
  139. package/src/features/shared/components/Paginator/Interval.tsx +4 -3
  140. package/src/features/shared/components/Paginator/NextPageButton.tsx +6 -2
  141. package/src/features/shared/components/SettingsDrawer/SettingsDrawer.tsx +6 -4
  142. package/src/features/shared/components/SettingsDrawer/SettingsDrawerListType.tsx +11 -10
  143. package/src/features/shared/components/SettingsDrawer/listTypeOptions.ts +10 -7
  144. package/src/features/shared/components/SortFilter/SortFilter.tsx +15 -8
  145. package/src/features/shared/components/Table/TableRow/TableRow.tsx +5 -1
  146. package/src/features/shared/components/VerticalNav/VerticalNavLink.tsx +7 -3
  147. package/src/features/shared/layouts/BaseTabsLayout/Navbar.tsx +28 -4
  148. package/src/features/shared/layouts/BaseTabsLayout/about-drawer/AboutDrawer.tsx +15 -5
  149. package/src/features/shared/layouts/BaseTabsLayout/base-tabs-layout.scss +24 -9
  150. package/src/features/shared/layouts/BaseTabsLayout/sidebar-drawer/SidebarDrawer.tsx +5 -2
  151. package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +10 -5
  152. package/src/features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout.tsx +7 -4
  153. package/src/features/shared/layouts/FinanceTabsLayout/FinanceTabsLayout.tsx +9 -4
  154. package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +7 -4
  155. package/src/features/shared/layouts/OrgUnitTabsLayout/OrgUnitTabLayout.tsx +3 -0
  156. package/src/features/shared/layouts/SumaPageLayout/FullSidebarNav.tsx +13 -7
  157. package/src/features/shared/layouts/SumaPageLayout/SumaSidebar.tsx +9 -5
  158. package/src/features/shared/localization/LocalizationContext.tsx +35 -0
  159. package/src/features/shared/localization/__tests__/createLocalize.test.ts +166 -0
  160. package/src/features/shared/localization/__tests__/get-localization-labels.service.test.ts +202 -0
  161. package/src/features/shared/localization/clients/LocalizationClient.ts +19 -0
  162. package/src/features/shared/localization/constants.ts +31 -0
  163. package/src/features/shared/localization/createLocalize.ts +78 -0
  164. package/src/features/shared/localization/services/get-localization-labels.service.ts +76 -0
  165. package/src/features/shared/localization/types.ts +66 -0
  166. package/src/features/shared/localization/withLocalization.tsx +22 -0
  167. package/src/features/shared/types/AuthRouteProps.ts +5 -0
  168. package/src/features/shared/types/LoaderData.ts +1 -0
  169. package/src/features/shared/utils/addresLabelToPropMapping.ts +10 -10
  170. package/src/features/shared/utils/constants.ts +1 -4
  171. package/src/features/shared/utils/getContractSettingsLinks.ts +17 -12
  172. package/src/features/shared/utils/getFinanceSettingsLinks.ts +14 -9
  173. package/src/features/shared/utils/getKeyByValue.ts +2 -2
  174. package/src/features/shared/utils/getOrganizationSettingsLinks.ts +13 -3
  175. package/src/features/shared/utils/getSumaListingSidebarLinks.ts +15 -10
  176. package/src/features/shared/utils/index.ts +2 -0
  177. package/src/features/shared/utils/routeLayoutMapping.ts +30 -30
  178. package/src/features/shared/utils/search.tsx +10 -0
  179. package/src/features/shared/utils/withAuth.tsx +6 -0
  180. package/src/features/shared/utils/withAuthLoader.ts +11 -0
  181. package/src/features/shared/utils/withLoaderErrorBoundary.ts +9 -0
  182. package/src/features/shared/utils/withProviders.tsx +13 -2
  183. package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +39 -27
  184. package/src/features/users/components/CreateUserDrawerWithUsername/CreateUserDrawerWithUsername.tsx +41 -39
  185. package/src/features/users/components/DeleteUserDrawer/DeleteUserDrawer.tsx +27 -23
  186. package/src/features/users/components/EmailTransactionalSection/EmailTransactionalSection.tsx +6 -8
  187. package/src/features/users/components/LoginField/LoginField.tsx +4 -4
  188. package/src/features/users/components/ReassignOrgUnitDrawer/ReassignOrgUnitDrawer.tsx +22 -19
  189. package/src/features/users/components/ResetPasswordDrawer/ResetPasswordDrawer.tsx +16 -21
  190. package/src/features/users/components/UpdateUserDrawer/UpdateUserDrawer.tsx +26 -15
  191. package/src/features/users/components/UpdateUserDrawerWithUsername/UpdateUserDrawerWithUsername.tsx +22 -8
  192. package/src/features/users/components/UserDropdownMenu/UserDropdownMenu.tsx +7 -5
  193. package/src/features/users/components/UserFormFields/UserFormFields.tsx +9 -8
  194. package/src/features/users/components/UsersCard/UsersCard.tsx +4 -2
  195. package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +26 -10
  196. package/src/features/users/layouts/UsersLayout/UsersLayout.tsx +12 -8
  197. package/src/pages/accounting-field.tsx +28 -15
  198. package/src/pages/address-details.tsx +37 -26
  199. package/src/pages/addresses.tsx +27 -12
  200. package/src/pages/budgets-details.tsx +25 -15
  201. package/src/pages/budgets.tsx +31 -17
  202. package/src/pages/buyer-organization-manager.tsx +23 -12
  203. package/src/pages/buying-policies.tsx +38 -20
  204. package/src/pages/buying-policy-details.tsx +20 -19
  205. package/src/pages/contracts.tsx +15 -1
  206. package/src/pages/credit-cards.tsx +30 -17
  207. package/src/pages/order-entry.tsx +26 -15
  208. package/src/pages/org-unit-details.tsx +20 -6
  209. package/src/pages/org-units.tsx +20 -6
  210. package/src/pages/payment-groups.tsx +15 -12
  211. package/src/pages/productAssortment.tsx +10 -1
  212. package/src/pages/profile.tsx +14 -1
  213. package/src/pages/role-details.tsx +19 -6
  214. package/src/pages/roles.tsx +27 -14
  215. package/src/pages/user-details.tsx +29 -17
  216. package/src/pages/users.tsx +11 -0
  217. package/vitest.config.ts +13 -0
  218. package/src/features/addresses/constants/messages.ts +0 -8
  219. package/src/features/credit-cards/constants/messages.ts +0 -6
@@ -0,0 +1,277 @@
1
+ # Multi-Locale E2E Validation (Org Account)
2
+
3
+ > **Status**: Done
4
+ > **Created**: 2026-07-09
5
+ > **Jira**: [B2BTEAM-3709](https://vtex-dev.atlassian.net/browse/B2BTEAM-3709)
6
+ > **Branch**: `feat/i18n`
7
+
8
+ ## Checklist coverage (Jira B2BTEAM-3709)
9
+
10
+ Legend: ✅ automated & passing · 🐛 automated & correctly failing (real bug found) · ⚠️ partial/indirect · ❌ still manual-only (not automatable, or needs real CMS content this environment doesn't have yet)
11
+
12
+ **1. Infraestrutura e comportamento base**
13
+ - ❌ Páginas carregam normalmente com endpoint de localização lento — SSR-only fetch, not interceptable from Cypress
14
+ - ⚠️ Chave CMS inexistente → fallback para a própria chave, sem crash — unit-tested (`createLocalize.test.ts`); E2E covers "no raw key visible" broadly (see below) but not one specific unknown key
15
+ - ✅ Labels do `shared` aparecem sem crash (checked on selector, About drawer, sidebar)
16
+ - 🐛 Trocar locale + recarregar/navegar reflete no idioma — **found a real bug**: see Finding 3
17
+ - ✅ Nenhuma requisição extra de localização no client (SSR/loader only)
18
+ - ✅ Erro (client-side) mostra texto traduzido, não chave CMS — best-effort, reproduces intermittently (Finding 2)
19
+
20
+ **2. Seletor de locale**
21
+ - ✅ Botão visível na navbar principal e na navbar de Org Unit Details
22
+ - ✅ Labels do drawer não vazias, sem chave CMS crua
23
+ - 🐛 Persistência do idioma entre navegação/reload — Finding 3
24
+ - ✅ Não quebra layout em viewport mobile/tablet
25
+
26
+ **3. Navegação, sidebar e títulos**
27
+ - ✅ Sidebar, About drawer, seletor — sem chaves CMS cruas visíveis (generic sweep)
28
+ - ❌ Tabs "Contract"/"Organization"/"Finance and Compliance" traduzidas — needs real CMS content
29
+ - ⚠️ Breadcrumb traduzido — checked for locale-prefixed hrefs where a clickable breadcrumb exists; content translation needs real CMS entries
30
+ - ❌ Loading skeleton com título traduzido — too timing-dependent to automate reliably
31
+ - ✅ About drawer sem chaves cruas
32
+ - ✅ "Start shopping" respeita locale (both navbars) — **the original bug, fixed**
33
+
34
+ **4. URLs localizadas**
35
+ - ✅ **Bug conhecido do `href="/"` na Navbar principal — corrigido e testado**
36
+ - ✅ Link Org Unit Details respeita locale
37
+ - ⚠️ Links em cards/tabelas/breadcrumbs/drawers — checked breadcrumb + hierarchy-tree click-area (the latter hits Finding 1); table/card links not exhaustively covered
38
+ - 🐛 Links internos mantêm prefixo ao navegar — Finding 1 (client-side) and Finding 3 (server redirect)
39
+
40
+ **5. Interpolação de strings**
41
+ - ✅ Paginação com números reais, não placeholders crus
42
+ - ✅ Delete User: nome do usuário interpolado em um link real, não placeholder cru
43
+ - ❌ Budget Add Success / Recipient form ReactNode interpolation — need multi-step seed setup (fresh org unit with zero budgets; create+edit recipient) not practical to bolt onto this spec without duplicating other suites' setup
44
+ - ❌ Toasts multi-linha, filtros/dropdowns dinâmicos — not covered
45
+
46
+ ## Findings (bugs discovered while validating, not part of this plugin's fix)
47
+
48
+ 1. **Client-side SPA navigation can drop the active locale.** Clicking between tabs while
49
+ a non-default locale is active intermittently lands on a URL without the locale prefix,
50
+ even though the equivalent direct/SSR request is always correct (proven via `curl`).
51
+ Points to `@faststore/core`'s `useLink_unstable`/router-locale sync, not this plugin.
52
+ 2. **Stale session/cart cookie causes a client-side error on locale switch outside the
53
+ selector's own flow.** Force-visiting a locale-prefixed page while a different-channel
54
+ session cookie is present can trigger the client error boundary (translated text
55
+ confirmed correct) on channel-sensitive pages (e.g. Assortments).
56
+ 3. **The buyer-portal root redirect drops the locale prefix.** Confirmed deterministically
57
+ via a plain `curl` (no browser/client JS): `GET /pt-BR/pvt/organization-account` returns
58
+ `302 Found` with `Location: /pvt/organization-account/org-unit/{id}` — no `/pt-BR`
59
+ prefix — so the landing page renders `lang="en-US"`. This is a **server-side redirect**
60
+ issue, unrelated to `resolveLink` or client navigation, and is the most actionable of the
61
+ three findings since it's 100% reproducible outside a browser.
62
+
63
+ These three are documented in `cypress/integration/localization.test.ts` (one test is
64
+ deliberately left red, reproducing Finding 3) and should be reported to whoever owns
65
+ `@faststore/core`'s experimental localization feature / the host-store's redirect logic.
66
+
67
+ ## Execution Notes
68
+
69
+ - **Code fix implemented**: `Navbar.tsx`'s "Start shopping" link now uses `resolveLink("/")`
70
+ via `useLink_unstable`, matching `OrgUnitDetailsNavbar`/`SidebarDrawer`. Verified with
71
+ `make lint`, `make typecheck` (0 new errors vs. the 143 pre-existing, unrelated
72
+ `@faststore/core`/`next/dynamic` type errors already on `feat/i18n`), and `make test`
73
+ (66/66 unit tests pass).
74
+ - **E2E test registered**: `cypress/integration/localization.test.ts` covers the checklist
75
+ items that are deterministically testable from the plugin repo — locale-prefixed "Start
76
+ shopping" links on both navbars, and the locale selector opening without crashing/blank
77
+ labels. `cy.login()` (`cypress/support/commands.ts`) now also accepts a `VTEX_AUTH_TOKEN`
78
+ env var to set the auth cookie directly, skipping the UI login flow — this wires up the
79
+ `VTEX_AUTH_TOKEN` secret already declared (but previously unused) in `.github/workflows/ci.yml`.
80
+ - **Live run: executed successfully** against `b2bfaststoredev.store`'s `feat/i18n-enable`
81
+ branch (which already has `contentSource: "CP"`, `localization.enabled: true`, `en-US`/
82
+ `pt-BR` locales, and the required `FS_DISCOVERY_APP_KEY`/`FS_DISCOVERY_APP_TOKEN` in
83
+ `vtex.env`), built and served locally (`faststore build && faststore serve`, Node 24) with
84
+ the plugin linked via `feat/i18n`. `cypress/integration/localization.test.ts` ran 3/3
85
+ passing, confirmed stable across 2 consecutive runs.
86
+ - **Real finding during the run**: clicking through the SPA (client-side Next.js navigation,
87
+ e.g. clicking "Profile" from the sidebar while on a `pt-BR`-prefixed page) intermittently
88
+ dropped the locale prefix from the resulting URL — reproduced 2 out of 3 times. Direct
89
+ `curl` requests to the same page, with and without the `/pt-BR` prefix, proved the
90
+ **server-rendered HTML is always correct** (`Navbar.tsx`'s fix included: the "Start
91
+ shopping" `href` is correctly `/pt-BR/` vs `/` depending on the request's locale, with
92
+ `Cache-Control: no-store` — no caching involved). So the SSR mechanism this plugin controls
93
+ (including the Navbar fix) is proven correct; the intermittent loss happens specifically
94
+ during **client-side (SPA) transitions**, which is `useLink_unstable`/Next.js router state
95
+ territory inside `@faststore/core`, outside this plugin's code. The test was adjusted to
96
+ assert against a direct, locale-prefixed re-request of the landed-on page (mirroring the
97
+ `curl` check) rather than the immediate post-click DOM state, so it deterministically tests
98
+ what this plugin renders. **Flagged separately for the Localization/`@faststore/core` team**:
99
+ SPA tab navigation while a non-default locale is active should be spot-checked for dropped
100
+ locale prefixes.
101
+ - **The spec still self-guards**: it visits a locale-prefixed URL first and skips (logs,
102
+ doesn't fail) if the environment doesn't resolve it to the Buyer Portal — so it stays green
103
+ against host-store environments where localization isn't enabled yet (e.g. `main`), and
104
+ enforces automatically wherever it is (like `feat/i18n-enable`, or once merged to `main`).
105
+ - **Added a 4th test** that verifies actual *content* changes with the locale (not just the
106
+ URL/routing), using the Assortments page title ("Assortments" vs "Sortimentos" — the one
107
+ page with real bilingual CMS entries today per this ticket). Also asserts `<html lang>`
108
+ changes. 4/4 passing, confirmed stable across 2 runs.
109
+ - **Second real finding while building that test**: force-visiting a locale-prefixed page
110
+ outside the selector's own Save+redirect flow, while a cart/session cookie from the
111
+ previous (default-locale) channel is still present, triggers a client-side error boundary
112
+ ("Something went wrong!") on the Assortments page specifically — the SSR HTML itself is
113
+ still correct (proven via direct `curl`), but client-side session/cart validation
114
+ (`ValidateSession`/`ValidateCartMutation`) appears to choke on the channel mismatch. The
115
+ test works around this by clearing all cookies except the auth cookie before the
116
+ locale-prefixed visit (mirroring what a fresh visit would look like). **Also worth flagging
117
+ to the Localization/`@faststore/core` team**, alongside the SPA-navigation finding above —
118
+ both point to the same gap: locale changes outside the official selector flow aren't fully
119
+ session-safe yet.
120
+ - **Still manual-only** (not automatable from Cypress, since labels/fetches happen
121
+ server-side in the loader): CMS latency/failure fallback, sidebar/breadcrumb/tab copy
122
+ correctness, and ReactNode-interpolated messages (Delete User, Budget success, Recipient
123
+ form) — these depend on actual CMS entries owned by the Localization team.
124
+
125
+ ## 1. Business Context
126
+
127
+ ### Problem Statement
128
+
129
+ `feat/i18n` implements the custom localization system described in
130
+ `specs/custom-localization-system.md` and goes beyond that spec's scope: it migrates
131
+ hardcoded strings from **all** Org Account domains to CMS-backed labels consumed via `t()`.
132
+ Before merging, the delivery must be validated end-to-end so that no user-visible string
133
+ regresses to a CMS key, hardcoded English, or a broken interpolation.
134
+
135
+ A code audit against the validation checklist (see ticket) found one concrete regression:
136
+ the **"Start shopping" link in the main `Navbar`** (rendered on every tabbed page — Profile,
137
+ Addresses, Users, etc.) uses a hardcoded `href="/"`, instead of resolving the link through
138
+ FastStore's locale-aware `resolveLink`. Every other equivalent link in the codebase
139
+ (`OrgUnitDetailsNavbar`, `SidebarDrawer`, `ProfileSummary`, table rows, breadcrumbs, etc.)
140
+ already goes through `useLink_unstable().resolveLink()`. As a result, clicking "Start
141
+ shopping" from the main navbar drops the user's selected locale instead of preserving it.
142
+
143
+ ### Goals
144
+
145
+ - Fix the "Start shopping" link in the main `Navbar` so it preserves the currently selected
146
+ locale, consistent with every other internal link in the portal.
147
+ - Leave a clear, actionable checklist of the remaining (non-code, browser-only) validation
148
+ items from the ticket for manual QA against `b2bfaststoredev.store`, since they require a
149
+ linked host store, a running browser session, and CMS entries — outside what a code-only
150
+ change can verify.
151
+
152
+ ### User Stories
153
+
154
+ #### US-1: "Start shopping" preserves the selected locale
155
+
156
+ - **Story**: As a buyer-portal user who has switched the UI language via the locale
157
+ selector, I want the "Start shopping" link in the main navbar to open the storefront in
158
+ that same locale, so that I don't lose my language context when leaving the portal.
159
+ - **Acceptance Criteria**:
160
+ - **Given** the user is on any tabbed page (e.g. Profile, Addresses, Users) with locale
161
+ `pt-BR` selected, **when** they click "Start shopping" in the main `Navbar`, **then** the
162
+ link target is prefixed with `/pt-BR` (or the active locale), matching the behavior of
163
+ the "Start shopping" link in `OrgUnitDetailsNavbar`.
164
+ - **Given** no locale is selected (default locale), **when** the user clicks "Start
165
+ shopping", **then** the link still opens the storefront root, with no regression to
166
+ current default behavior.
167
+
168
+ ### Key Scenarios
169
+
170
+ | Scenario | Pre-conditions | Steps | Expected Result |
171
+ |---|---|---|---|
172
+ | Happy path — locale preserved | Locale switched to `pt-BR` via `LocalizationButton` | Click "Start shopping" in main `Navbar` | New tab opens `/pt-BR/` (or active locale prefix), not bare `/` |
173
+ | Edge case — default locale | No locale switch performed | Click "Start shopping" | Opens storefront root as before (no regression) |
174
+ | Consistency check | Navigate to `/org-unit-details` | Compare "Start shopping" target in `OrgUnitDetailsNavbar` vs main `Navbar` | Both links resolve through the same `resolveLink` mechanism and produce equivalent locale-aware hrefs |
175
+
176
+ ### Functional Requirements
177
+
178
+ - **FR-001**: The main `Navbar`'s "Start shopping" link must resolve its `href` through
179
+ `useLink_unstable().resolveLink()`, the same mechanism already used by
180
+ `OrgUnitDetailsNavbar`, `SidebarDrawer`, and other internal links.
181
+
182
+ ### Non-Functional Requirements
183
+
184
+ - No new runtime dependencies; reuse the existing `@faststore/core/experimental` API already
185
+ imported in `Navbar.tsx` (`LocalizationButton_unstable`) — `useLink_unstable` is exported
186
+ from the same experimental surface.
187
+ - No visual/layout change: only the resolved `href` value changes, not the link's markup or
188
+ styling.
189
+
190
+ ### Out of Scope
191
+
192
+ - All other checklist items from B2BTEAM-3709 that require a running, linked host store,
193
+ browser DevTools inspection, or live CMS entries (fallback behavior under CMS latency,
194
+ locale persistence across navigation, sidebar/breadcrumb/tab translations, interpolation
195
+ correctness in Delete User / Budget / Recipient flows, etc.). These are manual/E2E QA
196
+ items to be executed against `b2bfaststoredev.store` and are tracked directly on the Jira
197
+ ticket checklist, not implemented here.
198
+ - Any translation content/copy work (CMS entries) — owned by the Localization team per the
199
+ ticket description.
200
+
201
+ ---
202
+
203
+ ## 2. Arch Decisions
204
+
205
+ ### Proposed Solution
206
+
207
+ Replace the hardcoded `href="/"` in `src/features/shared/layouts/BaseTabsLayout/Navbar.tsx`
208
+ with `resolveLink("/")`, obtained from `useLink_unstable()` (already the pattern used
209
+ elsewhere in the codebase, e.g. `SidebarDrawer.tsx`). This is a one-line, isolated fix with
210
+ no architectural changes to the localization system itself.
211
+
212
+ ### Alternatives Considered
213
+
214
+ | Alternative | Pros | Cons | Verdict |
215
+ |---|---|---|---|
216
+ | **A. Use `resolveLink("/")` via `useLink_unstable` (chosen)** | Matches existing convention across the codebase; zero new dependencies; minimal diff | None significant | **Accepted** |
217
+ | B. Manually prepend locale from `useLocalization`/router state | Avoids depending on experimental FastStore API | Duplicates logic FastStore already solves; localization context doesn't carry the active locale today | Rejected |
218
+
219
+ ### Risks & Mitigations
220
+
221
+ | Risk | Impact | Likelihood | Mitigation |
222
+ |---|---|---|---|
223
+ | `useLink_unstable` behaves differently in SSR vs. client for this link (it's rendered eagerly, unlike `LocalizationButton` which is `dynamic({ ssr: false })`) | Low | Low | Mirror the exact usage already proven in `SidebarDrawer.tsx` / `OrgUnitDetailsNavbar.tsx`, which render `resolveLink` without SSR guards |
224
+
225
+ ### Key Decisions
226
+
227
+ #### Decision 1: Reuse `useLink_unstable().resolveLink`, don't introduce a new abstraction
228
+
229
+ - **Status**: Accepted
230
+ - **Context**: Every other internal link in the portal already resolves through this hook.
231
+ Introducing a different mechanism just for this link would create inconsistency.
232
+ - **Decision**: Import `useLink_unstable as useLink` from `@faststore/core/experimental` in
233
+ `Navbar.tsx`, call `const { resolveLink } = useLink()`, and use `resolveLink("/")` as the
234
+ `href`.
235
+ - **Consequences**: One-line behavioral fix; no new patterns introduced; consistent with
236
+ `OrgUnitDetailsNavbar` and `SidebarDrawer`.
237
+
238
+ ### Implementation Plan
239
+
240
+ 1. Update `src/features/shared/layouts/BaseTabsLayout/Navbar.tsx`: import `useLink_unstable`,
241
+ call it, and replace `href="/"` with `href={resolveLink("/")}` on the "Start shopping"
242
+ link.
243
+ 2. Add/extend a test for `Navbar` (if a test file exists) asserting the link's `href` uses
244
+ `resolveLink` output.
245
+ 3. `make check` (lint + typecheck + test).
246
+ 4. Hand off the remaining checklist items (browser/CMS-dependent) to manual QA against
247
+ `b2bfaststoredev.store`.
248
+
249
+ ---
250
+
251
+ ## 3. Technical Contract
252
+
253
+ ### Data Models
254
+
255
+ None — no new data models; this fix only changes how an existing `href` string is computed.
256
+
257
+ ### Interfaces
258
+
259
+ - `useLink_unstable(): { resolveLink: (path: string) => string }` — existing FastStore
260
+ experimental hook, already used in this codebase (e.g.
261
+ `src/features/shared/layouts/BaseTabsLayout/sidebar-drawer/SidebarDrawer.tsx`).
262
+
263
+ ### Integration Points
264
+
265
+ - `src/features/shared/layouts/BaseTabsLayout/Navbar.tsx` — sole file changed.
266
+
267
+ ### Invariants & Constraints
268
+
269
+ - The "Start shopping" link must always resolve through `resolveLink`, never a hardcoded
270
+ path, to stay consistent with the rest of the portal's internal links.
271
+ - No change to the link's visible label, target (`_blank`), or `data-fs-*` attributes.
272
+
273
+ ### Files to Create / Change
274
+
275
+ | File | Change |
276
+ |---|---|
277
+ | `src/features/shared/layouts/BaseTabsLayout/Navbar.tsx` | Replace hardcoded `href="/"` with `resolveLink("/")` via `useLink_unstable` |
@@ -0,0 +1,12 @@
1
+ // Stub for `discovery.config` — provided by the host store at runtime.
2
+ // This file is only loaded in the unit-test environment (via vitest alias).
3
+ // Keep all fields that are accessed anywhere in src/ so unrelated unit tests
4
+ // don't crash when they transitively import a module that reads this config.
5
+ const discoveryConfig = {
6
+ api: { storeId: "test-store" },
7
+ secureSubdomain: "https://test-store.vtex.com",
8
+ storeUrl: "https://test-store.vtex.com",
9
+ seo: { title: "Test Store" },
10
+ };
11
+
12
+ export default discoveryConfig;
@@ -5,10 +5,13 @@ import {
5
5
  ErrorMessage,
6
6
  InputText,
7
7
  } from "../../../shared/components";
8
+ import { useLocalization } from "../../../shared/localization/LocalizationContext";
8
9
 
9
10
  type AccountingConfirmDeleteProps = {
10
11
  title: string | ReactNode;
11
12
  confirmTerm?: string;
13
+ confirmLabel?: string;
14
+ confirmRequiredMessage?: string;
12
15
  loading?: boolean;
13
16
  children?: string | ReactNode;
14
17
  onConfirm?: () => void;
@@ -20,11 +23,18 @@ const LABEL_MAX_LENGTH = 30;
20
23
  export const AccountingConfirmDelete = ({
21
24
  title,
22
25
  confirmTerm,
26
+ confirmLabel,
27
+ confirmRequiredMessage,
23
28
  close,
24
29
  loading,
25
30
  onConfirm,
26
31
  children,
27
32
  }: AccountingConfirmDeleteProps) => {
33
+ const { t } = useLocalization();
34
+ const inputLabel = confirmLabel ?? t("accountingFields.forms.fieldLabel");
35
+ const requiredMessage =
36
+ confirmRequiredMessage ??
37
+ t("accountingFields.validation.fieldLabelRequired");
28
38
  const [confirmField, setConfirmField] = useState("");
29
39
  const [isTouched, setIsTouched] = useState(false);
30
40
 
@@ -44,7 +54,7 @@ export const AccountingConfirmDelete = ({
44
54
  {confirmTerm && (
45
55
  <form data-fs-bp-accounting-confirm-delete-form>
46
56
  <InputText
47
- label="Field label"
57
+ label={inputLabel}
48
58
  value={confirmField}
49
59
  onChange={(e) =>
50
60
  setConfirmField(
@@ -58,7 +68,7 @@ export const AccountingConfirmDelete = ({
58
68
  <div data-fs-bp-accounting-form-legend>
59
69
  <ErrorMessage
60
70
  show={isTouched && !confirmFieldIsValid}
61
- message="Field label is required"
71
+ message={requiredMessage}
62
72
  />
63
73
  <InputText.Legend>
64
74
  {confirmField.length}/{LABEL_MAX_LENGTH}
@@ -69,7 +79,7 @@ export const AccountingConfirmDelete = ({
69
79
  </BasicDrawer.Body>
70
80
  <BasicDrawer.Footer>
71
81
  <BasicDrawer.Button variant="ghost" onClick={close} disabled={loading}>
72
- Cancel
82
+ {t("shared.buttons.cancel")}
73
83
  </BasicDrawer.Button>
74
84
  <BasicDrawer.Button
75
85
  variant="danger"
@@ -77,7 +87,7 @@ export const AccountingConfirmDelete = ({
77
87
  onClick={handleDeleteClick}
78
88
  disabled={disableDeleteBtn}
79
89
  >
80
- Delete
90
+ {t("shared.buttons.delete")}
81
91
  </BasicDrawer.Button>
82
92
  </BasicDrawer.Footer>
83
93
  </>
@@ -1,4 +1,5 @@
1
1
  import { BasicDrawer } from "../../../shared/components";
2
+ import { useLocalization } from "../../../shared/localization/LocalizationContext";
2
3
 
3
4
  type AccountingFieldConfirmEditProps = {
4
5
  onConfirm?: () => void;
@@ -13,16 +14,20 @@ export const AccountingFieldConfirmEdit = ({
13
14
  onConfirm,
14
15
  loading = false,
15
16
  }: AccountingFieldConfirmEditProps) => {
17
+ const { t } = useLocalization();
18
+
16
19
  return (
17
20
  <>
18
- <BasicDrawer.Heading onBack={onBack} title="Confirm field update" />
21
+ <BasicDrawer.Heading
22
+ onBack={onBack}
23
+ title={t("accountingFields.drawers.confirmFieldUpdateTitle")}
24
+ />
19
25
  <BasicDrawer.Body>
20
26
  <p data-fs-bp-accounting-field-confirm-edit-text>
21
- This accounting field is used by all organizational units. Updates
22
- will affect all of them.
27
+ {t("accountingFields.messages.confirmFieldUpdateDescription")}
23
28
  </p>
24
29
  <p data-fs-bp-accounting-field-confirm-edit-text>
25
- Proceed with the update?
30
+ {t("accountingFields.messages.proceedWithUpdate")}
26
31
  </p>
27
32
  </BasicDrawer.Body>
28
33
  <BasicDrawer.Footer>
@@ -31,14 +36,14 @@ export const AccountingFieldConfirmEdit = ({
31
36
  onClick={onCancel}
32
37
  disabled={loading}
33
38
  >
34
- Cancel
39
+ {t("shared.buttons.cancel")}
35
40
  </BasicDrawer.Button>
36
41
  <BasicDrawer.Button
37
42
  variant="confirm"
38
43
  isLoading={loading}
39
44
  onClick={onConfirm}
40
45
  >
41
- Confirm
46
+ {t("shared.buttons.confirm")}
42
47
  </BasicDrawer.Button>
43
48
  </BasicDrawer.Footer>
44
49
  </>
@@ -9,6 +9,7 @@ import {
9
9
 
10
10
  import { BasicDropdownMenu, Icon } from "../../../shared/components";
11
11
  import { useDrawerProps } from "../../../shared/hooks";
12
+ import { useLocalization } from "../../../shared/localization/LocalizationContext";
12
13
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
13
14
  import { CreateAccountingValueDrawer } from "../CreateAccountingValueDrawer/CreateAccountingValueDrawer";
14
15
  import { DeleteAccountingFieldDrawer } from "../DeleteAccountingFieldDrawer/DeleteAccountingFieldDrawer";
@@ -31,6 +32,7 @@ export const AccountingFieldDropdown = ({
31
32
  contractId,
32
33
  refreshList,
33
34
  }: AccountingFieldDropdownProps) => {
35
+ const { t } = useLocalization();
34
36
  const router = useRouter();
35
37
  const route = buyerPortalRoutes.accountingFields({
36
38
  orgUnitId,
@@ -80,11 +82,11 @@ export const AccountingFieldDropdown = ({
80
82
  <BasicDropdownMenu>
81
83
  <DropdownItem onClick={openCreateAccountingValueDrawer}>
82
84
  <Icon name="Add" width={ICON_SIZE} height={ICON_SIZE} />
83
- Add values
85
+ {t("accountingFields.dropdown.addValues")}
84
86
  </DropdownItem>
85
87
  <DropdownItem onClick={openEditAccountingFieldDrawer}>
86
88
  <Icon name="EditSettings" width={ICON_SIZE} height={ICON_SIZE} />
87
- Field settings
89
+ {t("accountingFields.dropdown.fieldSettings")}
88
90
  </DropdownItem>
89
91
  <BasicDropdownMenu.Separator />
90
92
  <DropdownItem
@@ -92,7 +94,7 @@ export const AccountingFieldDropdown = ({
92
94
  onClick={openDeleteAccountingFieldDrawer}
93
95
  >
94
96
  <Icon name="Delete" width={ICON_SIZE} height={ICON_SIZE} />
95
- Delete
97
+ {t("shared.buttons.delete")}
96
98
  </DropdownItem>
97
99
  </BasicDropdownMenu>
98
100
  </Dropdown>
@@ -14,6 +14,7 @@ import {
14
14
  SettingsDrawerContext,
15
15
  type SettingsDrawerContextType,
16
16
  } from "../../../shared/components/SettingsDrawer/SettingsDrawerContext";
17
+ import { useLocalization } from "../../../shared/localization/LocalizationContext";
17
18
 
18
19
  import type {
19
20
  AccountingFieldLevel,
@@ -42,6 +43,7 @@ export function AccountingFieldForm({
42
43
  isEdit = false,
43
44
  context = {},
44
45
  }: AccountingFieldFormProps) {
46
+ const { t } = useLocalization();
45
47
  const [isTouched, setIsTouched] = useState(false);
46
48
  const [formData, setFormData] =
47
49
  useState<AccountingFieldFormData>(initialData);
@@ -67,8 +69,8 @@ export function AccountingFieldForm({
67
69
  );
68
70
 
69
71
  const listTypeOptions = useMemo(
70
- () => createListTypeOptions(accountingFieldPlural),
71
- [accountingFieldPlural]
72
+ () => createListTypeOptions(accountingFieldPlural, t),
73
+ [accountingFieldPlural, t]
72
74
  );
73
75
 
74
76
  return (
@@ -86,11 +88,12 @@ export function AccountingFieldForm({
86
88
  {isEdit ? (
87
89
  <>
88
90
  <p data-fs-bp-edit-accounting-field-text>
89
- Set how buyers in this unit should enter {initialData.name}s
90
- during checkout
91
+ {t("accountingFields.messages.editFieldDescription", [
92
+ initialData.name,
93
+ ])}
91
94
  </p>
92
95
  <SettingsDrawer.ListType
93
- title="List type"
96
+ title={t("accountingFields.settings.listTypeTitle")}
94
97
  name={`${initialData.name}-list-type`}
95
98
  value={listType}
96
99
  onChange={setListType}
@@ -99,13 +102,12 @@ export function AccountingFieldForm({
99
102
  </>
100
103
  ) : (
101
104
  <p data-fs-bp-accounting-field-form-label>
102
- Add and configure up to 20 custom accounting fields used by buyers
103
- at checkout
105
+ {t("accountingFields.messages.createFieldDescription")}
104
106
  </p>
105
107
  )}
106
108
  <div data-fs-bp-accounting-field-form-item>
107
109
  <InputText
108
- label="Field label"
110
+ label={t("accountingFields.forms.fieldLabel")}
109
111
  value={formData.name}
110
112
  hasError={isTouched && !labelFieldIsValid}
111
113
  name="field-label"
@@ -121,7 +123,7 @@ export function AccountingFieldForm({
121
123
  icon={
122
124
  <Tooltip
123
125
  placement="left-center"
124
- content="Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium, eum."
126
+ content="" // TODO: Add message
125
127
  >
126
128
  <Icon name="InfoFilled" width={20} height={20} />
127
129
  </Tooltip>
@@ -130,7 +132,7 @@ export function AccountingFieldForm({
130
132
  <div data-fs-bp-accounting-form-legend>
131
133
  <ErrorMessage
132
134
  show={isTouched && !labelFieldIsValid}
133
- message="Field label is required"
135
+ message={t("accountingFields.validation.fieldLabelRequired")}
134
136
  />
135
137
  <InputText.Legend>
136
138
  {formData.name.length}/{LABEL_MAX_LENGTH}
@@ -139,7 +141,7 @@ export function AccountingFieldForm({
139
141
  </div>
140
142
  <div data-fs-bp-accounting-field-form-item>
141
143
  <p data-fs-bp-accounting-field-form-label className="radio">
142
- Input level
144
+ {t("accountingFields.forms.inputLevel")}
143
145
  </p>
144
146
  <RadioGroup
145
147
  name="level"
@@ -152,24 +154,24 @@ export function AccountingFieldForm({
152
154
  }
153
155
  >
154
156
  <RadioOption
155
- label="Order level - Applies to the entire order"
157
+ label={t("accountingFields.forms.orderLevel")}
156
158
  name="level"
157
159
  value="order"
158
160
  >
159
- Order level - Applies to the entire order
161
+ {t("accountingFields.forms.orderLevel")}
160
162
  </RadioOption>
161
163
  <RadioOption
162
- label="Item level - Applies to each item in the cart"
164
+ label={t("accountingFields.forms.itemLevel")}
163
165
  name="level"
164
166
  value="item"
165
167
  >
166
- Item level - Applies to each item in the cart
168
+ {t("accountingFields.forms.itemLevel")}
167
169
  </RadioOption>
168
170
  </RadioGroup>
169
171
  </div>
170
172
  <div data-fs-bp-accounting-field-form-item>
171
173
  <p data-fs-bp-accounting-field-form-label className="radio">
172
- Input requirement
174
+ {t("accountingFields.forms.inputRequirement")}
173
175
  </p>
174
176
  <RadioGroup
175
177
  name="requirement"
@@ -181,18 +183,26 @@ export function AccountingFieldForm({
181
183
  }))
182
184
  }
183
185
  >
184
- <RadioOption label="Required" name="requirement" value="true">
185
- Required
186
+ <RadioOption
187
+ label={t("accountingFields.forms.required")}
188
+ name="requirement"
189
+ value="true"
190
+ >
191
+ {t("accountingFields.forms.required")}
186
192
  </RadioOption>
187
- <RadioOption label="Optional" name="requirement" value="false">
188
- Optional
193
+ <RadioOption
194
+ label={t("accountingFields.forms.optional")}
195
+ name="requirement"
196
+ value="false"
197
+ >
198
+ {t("accountingFields.forms.optional")}
189
199
  </RadioOption>
190
200
  </RadioGroup>
191
201
  </div>
192
202
  <div data-fs-bp-accounting-field-form-item>
193
203
  <CheckboxField
194
204
  id="accounting-field-form-enable"
195
- label="Enable open text input so buyers can enter a value manually at checkout"
205
+ label={t("accountingFields.forms.enableOpenTextInput")}
196
206
  defaultChecked={formData.enabled}
197
207
  onChange={(e) =>
198
208
  setFormData((data) => ({
@@ -206,7 +216,7 @@ export function AccountingFieldForm({
206
216
  </BasicDrawer.Body>
207
217
  <BasicDrawer.Footer>
208
218
  <BasicDrawer.Button variant="ghost" onClick={close} disabled={loading}>
209
- Cancel
219
+ {t("shared.buttons.cancel")}
210
220
  </BasicDrawer.Button>
211
221
  <BasicDrawer.Button
212
222
  variant="confirm"
@@ -214,7 +224,7 @@ export function AccountingFieldForm({
214
224
  isLoading={loading}
215
225
  onClick={() => formRef.current?.requestSubmit()}
216
226
  >
217
- {isEdit ? "Save" : "Create"}
227
+ {isEdit ? t("shared.buttons.save") : t("shared.buttons.create")}
218
228
  </BasicDrawer.Button>
219
229
  </BasicDrawer.Footer>
220
230
  </SettingsDrawerContext.Provider>
@@ -1,4 +1,5 @@
1
1
  import { BasicDrawer } from "../../../shared/components";
2
+ import { useLocalization } from "../../../shared/localization/LocalizationContext";
2
3
 
3
4
  import type { AccountingField } from "../../types";
4
5
 
@@ -17,20 +18,23 @@ export const AccountingValueConfirmEdit = ({
17
18
  onConfirm,
18
19
  loading = false,
19
20
  }: AccountingValueConfirmEditProps) => {
21
+ const { t } = useLocalization();
22
+
20
23
  return (
21
24
  <>
22
25
  <BasicDrawer.Heading
23
- title={`Confirm ${accountingField.name} update`}
26
+ title={t("accountingFields.drawers.confirmValueUpdateTitle", [
27
+ accountingField.name,
28
+ ])}
24
29
  onClose={onCancel}
25
30
  onBack={onBack}
26
31
  />
27
32
  <BasicDrawer.Body>
28
33
  <p data-fs-bp-accounting-value-confirm-edit-text>
29
- This value may be used by multiple units. <br /> Updates will affect
30
- all of them.
34
+ {t("accountingFields.messages.confirmValueUpdateDescription")}
31
35
  </p>
32
36
  <p data-fs-bp-accounting-value-confirm-edit-text>
33
- Proceed with the update?
37
+ {t("accountingFields.messages.proceedWithUpdate")}
34
38
  </p>
35
39
  </BasicDrawer.Body>
36
40
  <BasicDrawer.Footer>
@@ -39,14 +43,14 @@ export const AccountingValueConfirmEdit = ({
39
43
  onClick={onCancel}
40
44
  disabled={loading}
41
45
  >
42
- Cancel
46
+ {t("shared.buttons.cancel")}
43
47
  </BasicDrawer.Button>
44
48
  <BasicDrawer.Button
45
49
  variant="confirm"
46
50
  isLoading={loading}
47
51
  onClick={onConfirm}
48
52
  >
49
- Confirm
53
+ {t("shared.buttons.confirm")}
50
54
  </BasicDrawer.Button>
51
55
  </BasicDrawer.Footer>
52
56
  </>