feat(): Translation settings + user configuration + admin hook and js sdk + dashboard (#14355)

* feat(): Translation settings + user configuration

* feat(): Translation settings + user configuration

* Create gentle-bees-grow.md

* add entities end point

* add entities end point

* add admin hook and js sdk method

* update changeset

* fix tests

* fix tests

* rm unnecessary copy

* update dashboard to use the new resources

* update dashboard to use the new resources

* update dashboard to use the new resources

* allow type inference through interface augmentation in the defineConfig of medusa-config

* allow type inference through interface augmentation in the defineConfig of medusa-config

* exclude id and _id props

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2025-12-19 15:29:48 +01:00
committed by GitHub
co-authored by Oli Juhl
parent 797878af26
commit b21a599d11
26 changed files with 1041 additions and 260 deletions
@@ -15,7 +15,11 @@ moduleIntegrationTestRunner<ITranslationModuleService>({
service: TranslationModuleService,
}).linkable
expect(Object.keys(linkable)).toEqual(["locale", "translation"])
expect(Object.keys(linkable)).toEqual([
"locale",
"translation",
"translationSettings",
])
Object.keys(linkable).forEach((key) => {
delete linkable[key].toJSON
@@ -40,6 +44,15 @@ moduleIntegrationTestRunner<ITranslationModuleService>({
field: "translation",
},
},
translationSettings: {
id: {
linkable: "translation_settings_id",
entity: "TranslationSettings",
primaryKey: "id",
serviceName: "translation",
field: "translationSettings",
},
},
})
})
@@ -647,11 +660,83 @@ moduleIntegrationTestRunner<ITranslationModuleService>({
})
})
describe("Settings", () => {
describe("getTranslatableFields", () => {
it("should return all translatable fields from database", async () => {
const fields = await service.getTranslatableFields()
expect(fields).toHaveProperty("product")
expect(fields).toHaveProperty("product_variant")
expect(fields.product).toEqual(
expect.arrayContaining(["title", "description"])
)
})
it("should return translatable fields for a specific entity type", async () => {
const fields = await service.getTranslatableFields("product")
expect(Object.keys(fields)).toEqual(["product"])
expect(fields.product).toEqual(
expect.arrayContaining(["title", "description"])
)
})
it("should return empty object for unknown entity type", async () => {
const fields = await service.getTranslatableFields("unknown_entity")
expect(fields).toEqual({})
})
})
describe("listing translations filters by configured fields", () => {
it("should only return configured fields in translations", async () => {
await service.createTranslations({
reference_id: "prod_filter_1",
reference: "product",
locale_code: "en-US",
translations: {
title: "Product Title",
description: "Product Description",
unconfigured_field: "Should be filtered out",
},
})
const translations = await service.listTranslations({
reference_id: "prod_filter_1",
})
expect(translations).toHaveLength(1)
expect(translations[0].translations).toHaveProperty("title")
expect(translations[0].translations).toHaveProperty("description")
expect(translations[0].translations).not.toHaveProperty(
"unconfigured_field"
)
})
it("should return empty translations for unconfigured entity types", async () => {
await service.createTranslations({
reference_id: "unconfigured_1",
reference: "unconfigured_entity",
locale_code: "en-US",
translations: {
field1: "Value 1",
field2: "Value 2",
},
})
const translations = await service.listTranslations({
reference_id: "unconfigured_1",
})
expect(translations).toHaveLength(1)
expect(translations[0].translations).toEqual({})
})
})
})
describe("Statistics", () => {
describe("getStatistics", () => {
it("should return statistics for a single entity type and locale", async () => {
// Create translations for 2 products with some fields filled
// Product has 4 translatable fields: title, description, material, subtitle
await service.createTranslations([
{
reference_id: "prod_stat_1",