feat(): Translation statistics (#14299)
* chore(): Translation statistics * chore(): improve statistics performances * add end point to get statistics * add tests * Create spicy-games-unite.md * feat(): add material and fix tests * feat(): add translatable api * feat(): add translatable api * fix tests * fix tests * fix tests * feedback
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
import {
|
||||
AdminBatchTranslations,
|
||||
AdminGetTranslationsParams,
|
||||
AdminTranslationStatistics,
|
||||
} from "./validators"
|
||||
import * as QueryConfig from "./query-config"
|
||||
import { DEFAULT_BATCH_ENDPOINTS_SIZE_LIMIT } from "../../../utils"
|
||||
@@ -29,4 +30,14 @@ export const adminTranslationsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
},
|
||||
middlewares: [validateAndTransformBody(AdminBatchTranslations)],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/translations/statistics",
|
||||
middlewares: [validateAndTransformQuery(AdminTranslationStatistics, {})],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/translations/settings",
|
||||
middlewares: [],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/framework/http"
|
||||
import { HttpTypes, ITranslationModuleService } from "@medusajs/framework/types"
|
||||
import {
|
||||
defineFileConfig,
|
||||
FeatureFlag,
|
||||
Modules,
|
||||
} from "@medusajs/framework/utils"
|
||||
import TranslationFeatureFlag from "../../../../feature-flags/translation"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse<HttpTypes.AdminTranslationSettingsResponse>
|
||||
) => {
|
||||
const translationService = req.scope.resolve<ITranslationModuleService>(
|
||||
Modules.TRANSLATION
|
||||
)
|
||||
const translatable_fields = translationService.getTranslatableFields()
|
||||
|
||||
res.json({
|
||||
translatable_fields,
|
||||
})
|
||||
}
|
||||
|
||||
defineFileConfig({
|
||||
isDisabled: () => !FeatureFlag.isFeatureEnabled(TranslationFeatureFlag.key),
|
||||
})
|
||||
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/framework/http"
|
||||
import { HttpTypes, ITranslationModuleService } from "@medusajs/framework/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
defineFileConfig,
|
||||
FeatureFlag,
|
||||
Modules,
|
||||
promiseAll,
|
||||
} from "@medusajs/framework/utils"
|
||||
import TranslationFeatureFlag from "../../../../feature-flags/translation"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest<
|
||||
unknown,
|
||||
HttpTypes.AdminTranslationStatisticsParams
|
||||
>,
|
||||
res: MedusaResponse<HttpTypes.AdminTranslationStatisticsResponse>
|
||||
) => {
|
||||
const translationService = req.scope.resolve<ITranslationModuleService>(
|
||||
Modules.TRANSLATION
|
||||
)
|
||||
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||
|
||||
const { locales, entity_types } = req.validatedQuery
|
||||
|
||||
// Fetch counts for each entity type in parallel
|
||||
const entityCounts = await promiseAll(
|
||||
entity_types.map(async (entityType) => {
|
||||
const { metadata } = await query
|
||||
.graph(
|
||||
{
|
||||
entity: entityType,
|
||||
fields: ["id"],
|
||||
pagination: { take: 1, skip: 0 },
|
||||
},
|
||||
{
|
||||
throwIfKeyNotFound: false,
|
||||
cache: { enable: true },
|
||||
}
|
||||
)
|
||||
.catch((e) => {
|
||||
const normalizedMessage = e.message.toLowerCase()
|
||||
if (
|
||||
normalizedMessage.includes("service with alias") &&
|
||||
normalizedMessage.includes("was not found")
|
||||
) {
|
||||
return { metadata: { count: 0 } }
|
||||
}
|
||||
throw e
|
||||
})
|
||||
return { entityType, count: metadata?.count ?? 0 }
|
||||
})
|
||||
)
|
||||
|
||||
const entities: Record<string, { count: number }> = {}
|
||||
for (const { entityType, count } of entityCounts) {
|
||||
entities[entityType] = { count }
|
||||
}
|
||||
|
||||
const statistics = await translationService.getStatistics({
|
||||
locales,
|
||||
entities,
|
||||
})
|
||||
|
||||
return res.json({
|
||||
statistics,
|
||||
})
|
||||
}
|
||||
|
||||
defineFileConfig({
|
||||
isDisabled: () => !FeatureFlag.isFeatureEnabled(TranslationFeatureFlag.key),
|
||||
})
|
||||
@@ -48,3 +48,19 @@ export const AdminBatchTranslations = createBatchBody(
|
||||
AdminCreateTranslation,
|
||||
AdminUpdateTranslation
|
||||
)
|
||||
|
||||
export type AdminTranslationStatisticsType = z.infer<
|
||||
typeof AdminTranslationStatistics
|
||||
>
|
||||
export const AdminTranslationStatistics = z
|
||||
.object({
|
||||
locales: z.union([z.string(), z.array(z.string())]),
|
||||
entity_types: z.union([z.string(), z.array(z.string())]),
|
||||
})
|
||||
.transform((data) => ({
|
||||
// Normalize to arrays for consistent handling
|
||||
locales: Array.isArray(data.locales) ? data.locales : [data.locales],
|
||||
entity_types: Array.isArray(data.entity_types)
|
||||
? data.entity_types
|
||||
: [data.entity_types],
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user