-
Building an application with Svelte and typesafe-i18n I'm seeking on best practices for storing and maintaining translation files.
Having a route: So far I have thought about the following approaches: Using single key nameconst en: BaseTranslation = {
ACCOUNT_SIGN_UP_FORM_LABEL_EMAIL: 'Email address',
ACCOUNT_SIGN_UP_FORM_LABEL_PASSWORD: 'Password',
ACCOUNT_SIGN_UP_FORM_VALIDATIONS_EMAIL_REQUIRED: 'Email address is required',
ACCOUNT_SIGN_UP_FORM_VALIDATIONS_EMAIL_INVALID_FORMAT: 'Email format is not valid',
ACCOUNT_SIGN_UP_FORM_VALIDATIONS_PASSWORD_REQUIRED: 'The password is required'
} Using objects to namespace each section/componentconst en: BaseTranslation = {
ACCOUNT: {
SIGN_UP: {
FORM: {
LABELS: {
EMAIL: 'Email address',
PASSWORD: 'Password',
SUBMIT: 'Create account',
},
VALIDATIONS: {
EMAIL: {
REQUIRED: 'Email address is required',
INVALID_FORMAT: 'Email format is not valid',
},
PASSWORD: {
REQUIRED: 'Password is required',
},
},
},
},
},
}; For big applications with many translations and pages, with continuous integration on features, improvements on wordings from the UX team, I'm wondering which would be the best take on these files. If there's any example project or any advices on configuration or approaches on loading these translation trees to reduce memory usage and encourage fast loading times would be great to have a peek on them. Thanks in advance for such a great tool! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Hi @EstebanBorai thanks for opening this discussion :) I would always recommend the object syntax for structuring your dictionaries. First of all: translation files are usually not that big and you could easilly store 500 translations in a single dictionary file and transfer it with about 10kb of network usage. I know we could (and also should) improve this but consider this not as such a big problem like transferring a similar amount of javascript library code that would also take some amount of time for parsing.
If you want to reduce the amount of transferred data even more, you would need to wait until this is implemented or go with your own solution. You could write some custom logic to get a namespace-like functionality: // file: src/i18n/i18n-custom.ts
import { i18nObject } from 'typesafe-i18n'
import { initFormatters } from './formatters'
import type { BaseTranslation, Formatters, Locales, Translation, TranslationFunctions } from './i18n-types'
import { baseLocale } from './i18n-util'
export type Namespace = keyof Translation
type TranslationLoaderWithNamespaces = Record<
Locales,
{
[Key in Namespace]: () => Promise<{
//@ts-ignore
default: (Key extends '' ? Translation : Translation[Key]) | BaseTranslation
}>
}
>
// you manually need to add the correct paths here
const localeTranslationLoaders: TranslationLoaderWithNamespaces = {
de: {
common: () => import(`./de/common`),
settings: () => import(`./de/settings`),
projects: () => import(`./de/projects`)
},
en: {
common: () => import(`./en/common`),
settings: () => import(`./en/settings`),
projects: () => import(`./en/projects`)
},
}
export const getTranslationForLocale = async (namespace: Namespace, locale: Locales) => {
const dictionaryToLoad = (localeTranslationLoaders[locale] || localeTranslationLoaders[baseLocale])
const namespaceToLoad = dictionaryToLoad[namespace]
const dictionary = (await (namespaceToLoad)()).default
return { [namespace]: dictionary }
}
const initI18n = async (locale: Locales = 'en', namespace: Namespace) => {
const translations = await getTranslationForLocale(namespace, locale)
const formatters = await initFormatters(locale)
const LL = i18nObject<Locales, Translation, TranslationFunctions, Formatters>(locale, translations, formatters)
// TODO: store LL in a writable store, context or simply return it
}
export { initI18n }
// file: src/i18n/en/index.ts
import type { BaseTranslation } from '../i18n-types'
import en_common from './common'
import en_projects from './projects'
import en_settings from './settings'
// this object is just here to be able to generate correct type definitions
const en: BaseTranslation = {
common: en_common,
settings: en_settings,
projects: en_projects,
}
export default en
// file: src/i18n/en/settings/index.ts
import type { BaseTranslation } from '../../i18n-types'
const en_settings: BaseTranslation = {
account: 'Account'
}
export default en_settings
// file: src/i18n/de/settings/index.ts
import type { Translation } from '../../i18n-types'
const de_settings: Translation['settings'] = {
account: 'Konto'
}
export default de_settings You then can call This solution does't allow nesting of namespaces, but you can define as many namespaces you need. If you have components that are shared between pages, you probably would end up with multiple I hope this example helps you. Let me know if something is unclear ;) edited: I unintentionally used the term |
Beta Was this translation helpful? Give feedback.
Hi @EstebanBorai thanks for opening this discussion :)
This is a good question and unfortunately I don't have a good answer yet.
I would always recommend the object syntax for structuring your dictionaries.
May I ask how big the dictionary in your application is?
First of all: translation files are usually not that big and you could easilly store 500 translations in a single dictionary file and transfer it with about 10kb of network usage. I know we could (and also should) improve this but consider this not as such a big problem like transferring a similar amount of javascript library code that would also take some amount of time for parsing.
typesafe-i18n
currently only transfers the cur…