feat(): Introduce translation module and preliminary application of them (#14189)
* feat(): Translation first steps * feat(): locale middleware * feat(): readonly links * feat(): feature flag * feat(): modules sdk * feat(): translation module re export * start adding workflows * update typings * update typings * test(): Add integration tests * test(): centralize filters preparation * test(): centralize filters preparation * remove unnecessary importy * fix workflows * Define StoreLocale inside Store Module * Link definition to extend Store with supported_locales * store_locale migration * Add supported_locales handling in Store Module * Tests * Accept supported_locales in Store endpoints * Add locales to js-sdk * Include locale list and default locale in Store Detail section * Initialize local namespace in js-sdk * Add locales route * Make code primary key of locale table to facilitate upserts * Add locales routes * Show locale code as is * Add list translations api route * Batch endpoint * Types * New batchTranslationsWorkflow and various updates to existent ones * Edit default locale UI * WIP * Apply translation agnostically * middleware * Apply translation agnostically * fix Apply translation agnostically * apply translations to product list * Add feature flag * fetch translations by batches of 250 max * fix apply * improve and test util * apply to product list * dont manage translations if no locale * normalize locale * potential todo * Protect translations routes with feature flag * Extract normalize locale util to core/utils * Normalize locale on write * Normalize locale for read * Use feature flag to guard translations UI across the board * Avoid throwing incorrectly when locale_code not present in partial updates * move applyTranslations util * remove old tests * fix util tests * fix(): product end points * cleanup * update lock * remove unused var * cleanup * fix apply locale * missing new dep for test utils * Change entity_type, entity_id to reference, reference_id * Remove comment * Avoid registering translations route if ff not enabled * Prevent registering express handler for disabled route via defineFileConfig * Add tests * Add changeset * Update test * fix integration tests, module and internals * Add locale id plus fixed * Allow to pass array of reference_id * fix unit tests * fix link loading * fix store route * fix sales channel test * fix tests --------- Co-authored-by: Nicolas Gorga <nicogorga11@gmail.com> Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
co-authored by
Nicolas Gorga
Oli Juhl
parent
fea3d4ec49
commit
6dc0b8bed8
@@ -0,0 +1,193 @@
|
||||
import { raw } from "@medusajs/framework/mikro-orm/core"
|
||||
import {
|
||||
Context,
|
||||
CreateTranslationDTO,
|
||||
DAL,
|
||||
FilterableTranslationProps,
|
||||
FindConfig,
|
||||
ITranslationModuleService,
|
||||
LocaleDTO,
|
||||
ModulesSdkTypes,
|
||||
TranslationTypes,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
MedusaContext,
|
||||
MedusaService,
|
||||
normalizeLocale,
|
||||
} from "@medusajs/framework/utils"
|
||||
import Locale from "@models/locale"
|
||||
import Translation from "@models/translation"
|
||||
|
||||
type InjectedDependencies = {
|
||||
baseRepository: DAL.RepositoryService
|
||||
translationService: ModulesSdkTypes.IMedusaInternalService<typeof Translation>
|
||||
localeService: ModulesSdkTypes.IMedusaInternalService<typeof Locale>
|
||||
}
|
||||
|
||||
export default class TranslationModuleService
|
||||
extends MedusaService<{
|
||||
Locale: {
|
||||
dto: TranslationTypes.LocaleDTO
|
||||
}
|
||||
Translation: {
|
||||
dto: TranslationTypes.TranslationDTO
|
||||
}
|
||||
}>({
|
||||
Locale,
|
||||
Translation,
|
||||
})
|
||||
implements ITranslationModuleService
|
||||
{
|
||||
protected baseRepository_: DAL.RepositoryService
|
||||
protected translationService_: ModulesSdkTypes.IMedusaInternalService<
|
||||
typeof Translation
|
||||
>
|
||||
protected localeService_: ModulesSdkTypes.IMedusaInternalService<
|
||||
typeof Locale
|
||||
>
|
||||
|
||||
constructor({
|
||||
baseRepository,
|
||||
translationService,
|
||||
localeService,
|
||||
}: InjectedDependencies) {
|
||||
super(...arguments)
|
||||
this.baseRepository_ = baseRepository
|
||||
this.translationService_ = translationService
|
||||
this.localeService_ = localeService
|
||||
}
|
||||
|
||||
static prepareFilters(
|
||||
filters: FilterableTranslationProps
|
||||
): FilterableTranslationProps {
|
||||
let { q, ...restFilters } = filters
|
||||
|
||||
if (q) {
|
||||
restFilters = {
|
||||
...restFilters,
|
||||
[raw(`translations::text ILIKE ?`, [`%${q}%`])]: [],
|
||||
}
|
||||
}
|
||||
|
||||
return restFilters
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
// @ts-expect-error
|
||||
async listTranslations(
|
||||
filters: FilterableTranslationProps = {},
|
||||
config: FindConfig<TranslationTypes.TranslationDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TranslationTypes.TranslationDTO[]> {
|
||||
const preparedFilters = TranslationModuleService.prepareFilters(filters)
|
||||
|
||||
const results = await this.translationService_.list(
|
||||
preparedFilters,
|
||||
config,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
TranslationTypes.TranslationDTO[]
|
||||
>(results)
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
// @ts-expect-error
|
||||
async listAndCountTranslations(
|
||||
filters: FilterableTranslationProps = {},
|
||||
config: FindConfig<TranslationTypes.TranslationDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<[TranslationTypes.TranslationDTO[], number]> {
|
||||
const preparedFilters = TranslationModuleService.prepareFilters(filters)
|
||||
|
||||
const [results, count] = await this.translationService_.listAndCount(
|
||||
preparedFilters,
|
||||
config,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return [
|
||||
await this.baseRepository_.serialize<TranslationTypes.TranslationDTO[]>(
|
||||
results
|
||||
),
|
||||
count,
|
||||
]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
createLocales(
|
||||
data: TranslationTypes.CreateLocaleDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<TranslationTypes.LocaleDTO[]>
|
||||
// @ts-expect-error
|
||||
createLocales(
|
||||
data: TranslationTypes.CreateLocaleDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<TranslationTypes.LocaleDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createLocales(
|
||||
data: TranslationTypes.CreateLocaleDTO | TranslationTypes.CreateLocaleDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TranslationTypes.LocaleDTO | TranslationTypes.LocaleDTO[]> {
|
||||
const dataArray = Array.isArray(data) ? data : [data]
|
||||
const normalizedData = dataArray.map((locale) => ({
|
||||
...locale,
|
||||
code: normalizeLocale(locale.code),
|
||||
}))
|
||||
|
||||
const createdLocales = await this.localeService_.create(
|
||||
normalizedData,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<LocaleDTO[]>(
|
||||
createdLocales
|
||||
)
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
createTranslations(
|
||||
data: CreateTranslationDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<TranslationTypes.TranslationDTO>
|
||||
|
||||
// @ts-expect-error
|
||||
createTranslations(
|
||||
data: CreateTranslationDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<TranslationTypes.TranslationDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createTranslations(
|
||||
data: CreateTranslationDTO | CreateTranslationDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
TranslationTypes.TranslationDTO | TranslationTypes.TranslationDTO[]
|
||||
> {
|
||||
const dataArray = Array.isArray(data) ? data : [data]
|
||||
const normalizedData = dataArray.map((translation) => ({
|
||||
...translation,
|
||||
locale_code: normalizeLocale(translation.locale_code),
|
||||
}))
|
||||
|
||||
const createdTranslations = await this.translationService_.create(
|
||||
normalizedData,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
TranslationTypes.TranslationDTO[]
|
||||
>(createdTranslations)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user