Fixes#9858
# The problems
There were several issues with custom i18n typing in the documentation
that were not detected because they did not occur in non-strict ts mode.
1. `Config['i18n']['translations']` didn't work, because i18n is an
optional property. As described in
[#9858](https://github.com/payloadcms/payload/issues/9858#issuecomment-2555814771),
some users were getting around this with
`NonNullable<Config['i18n']>['translations']`
2. [The trick being attempted in
`i18n`](36e152d69d/packages/payload/src/config/types.ts (L1034))
to customize and extend the `DefaultTranslationObject` does not work.
`i18n?: I18nOptions<{} | DefaultTranslationsObject> // loosen the type
here to allow for custom translations`.
If you want to verify this, you can use the following code example:
```ts
import type { Config } from 'payload'
const translation: NonNullable<Config['i18n']>['translations'] = {
en: {
authentication: {
aaaaa: 'aaaaa', // I chose `authentication.aaaa` to appear first in intellisense
}
},
}
translation.en?.authentication // Property 'authentication' does not
// exist on type '{} | { authentication: { account: string...
// so this option doesn't let you access the keys because of the join with `{}`,
// and even if it did, it's not adding `aaaa` as a key.
```
3. In places where the `t` function is exposed in a callback, you cannot
do what the documentation says:
`{ t }: { t: TFunction<CustomTranslationsKeys | DefaultTranslationKeys>
}`
The reason for this is that the callback is exposed as a `LabelFunction`
type but without type arguments, and as a default it uses
`DefaultTranslationKeys`, which does not allow additional keys.
If you want to verify this, you can use the following code example:
```ts
// Make sure to test this with ts in strict mode
const _labelFn: LabelFunction = ({ t }: { t: TFunction<'extraKey' | DefaultTranslationKeys> }) => ""
// Type '"extraKey"' is not assignable to type
// '"authentication:account" | ... 441 more ... | "version:versionCount"'.
```
# The solution
Point 1 is a documentation issue. We could use `NonNullable`, or expose
the `I18nOptions` type, or simply not define the custom translation type
(which makes sense because if you put it in the config, ts will warn you
anyway).
Points 2 and 3 should ideally be corrected at the type level, but it
would imply a breaking change.
For now, I have corrected them at the documentation level, using an
alternative for point 2 and a type cast for point 3.
Maybe in payload v4 we should revisit this.