Skip to content

Commit d7f1ea2

Browse files
authored
fix: inject custom translations into supportedLanguages in sanitization (#14549)
## Description Automatically injects custom translations from `i18n.translations` into `supportedLanguages` during config sanitization. This allows translation functions like `({ t }) => t('namespace:key')` to work with user-defined custom translations, not just the default translations from `@payloadcms/translations`. ## Problem Currently, when users define custom translations in their config: ```typescript i18n: { translations: { de: { 'my-namespace': { customKey: 'Wert' } } } } ``` These translations are **not** accessible to the `t` function used in field labels and options. The `t` function only searches in `config.i18n.supportedLanguages[lang].translations`, causing custom translations to be ignored. This issue was discovered while implementing translation support for plugins in PR #14548, where radio button options using `label: ({ t }) => t('plugin-redirects:key')` failed to translate for custom languages. ## Solution During config sanitization (in `packages/payload/src/config/sanitize.ts`), the code now: 1. Iterates through all languages in `i18n.translations` 2. For existing languages in `supportedLanguages`: merges custom translations with existing ones 3. For new languages: creates them using English as a template, then merges custom translations This ensures that **all custom translations** defined by users or plugins are automatically available to the `t` function throughout the application.
1 parent 844f99f commit d7f1ea2

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

packages/payload/src/config/sanitize.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AcceptedLanguages } from '@payloadcms/translations'
1+
import type { AcceptedLanguages, Language } from '@payloadcms/translations'
22

33
import { en } from '@payloadcms/translations/languages/en'
44
import { deepMergeSimple } from '@payloadcms/translations/utilities'
@@ -176,6 +176,35 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise<SanitizedC
176176
i18nConfig.translations
177177
}
178178

179+
// Inject custom translations from i18n.translations into supportedLanguages
180+
// This allows label functions like ({ t }) => t('namespace:key') to work with custom translations
181+
// that users define in their config, not just the default translations from @payloadcms/translations
182+
if (i18nConfig.translations && typeof i18nConfig.translations === 'object') {
183+
Object.keys(i18nConfig.translations).forEach((lang) => {
184+
const langKey = lang as AcceptedLanguages
185+
const customTranslations = i18nConfig.translations[langKey]
186+
187+
if (customTranslations && typeof customTranslations === 'object') {
188+
const existingLang = i18nConfig.supportedLanguages[langKey]
189+
190+
if (existingLang) {
191+
// Language exists - merge custom translations with existing
192+
const merged = deepMergeSimple(existingLang.translations || {}, customTranslations)
193+
// @ts-expect-error - merging custom translations into language config
194+
i18nConfig.supportedLanguages[langKey] = { ...existingLang, translations: merged }
195+
} else {
196+
// Language doesn't exist - create it using 'en' as template
197+
// Merge en.translations (general, authentication, etc.) with custom translations
198+
const mergedTranslations = deepMergeSimple(en.translations, customTranslations)
199+
i18nConfig.supportedLanguages[langKey] = {
200+
...en,
201+
translations: mergedTranslations,
202+
} as Language<typeof en.translations>
203+
}
204+
}
205+
})
206+
}
207+
179208
config.i18n = i18nConfig
180209

181210
const richTextSanitizationPromises: Array<(config: SanitizedConfig) => Promise<void>> = []

0 commit comments

Comments
 (0)