Skip to content

Commit

Permalink
Merge pull request #59 from Marvell-Consulting/SW-159
Browse files Browse the repository at this point in the history
SW-159: Translation export & import
  • Loading branch information
wheelsandcogs authored Dec 19, 2024
2 parents 1e11690 + 124f757 commit 2c4ed2b
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 20 deletions.
19 changes: 12 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { providerRouter } from './route/provider';
import { topicRouter } from './route/topic';
import { organisationRouter } from './route/organisation';
import { teamRouter } from './route/team';
import { translationRouter } from './route/translation';

export const initDb = async (): Promise<DatabaseManager> => {
const dbManager = new DatabaseManager(logger);
Expand Down Expand Up @@ -57,6 +58,7 @@ app.use('/provider', rateLimiter, passport.authenticate('jwt', { session: false
app.use('/topic', rateLimiter, passport.authenticate('jwt', { session: false }), topicRouter);
app.use('/organisation', rateLimiter, passport.authenticate('jwt', { session: false }), organisationRouter);
app.use('/team', rateLimiter, passport.authenticate('jwt', { session: false }), teamRouter);
app.use('/translation', rateLimiter, passport.authenticate('jwt', { session: false }), translationRouter);

app.use(errorHandler);

Expand Down
24 changes: 21 additions & 3 deletions src/dtos/tasklist-state-dto.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { every } from 'lodash';

import { Dataset } from '../entities/dataset/dataset';
import { DimensionInfo } from '../entities/dataset/dimension-info';
import { DimensionType } from '../enums/dimension-type';
import { TaskStatus } from '../enums/task-status';
import { translatableMetadataKeys } from '../types/translatable-metadata';

import { DimensionStatus } from './dimension-status';
import { MeasureDTO } from './measure-dto';

export class TasklistStateDTO {
datatable: TaskStatus;
Expand Down Expand Up @@ -33,6 +35,17 @@ export class TasklistStateDTO {
when: TaskStatus;
};

public static translationStatus(dataset: Dataset): TaskStatus {
const metaFullyTranslated = dataset.datasetInfo?.every((info) => {
return every(translatableMetadataKeys, (key) => {
// ignore roundingDescription if rounding isn't applied, otherwise check some data exists
return key === 'roundingDescription' && !info.roundingApplied ? true : Boolean(info[key]);
});
});

return metaFullyTranslated ? TaskStatus.Completed : TaskStatus.Incomplete;
}

public static fromDataset(dataset: Dataset, lang: string): TasklistStateDTO {
const info = dataset.datasetInfo?.find((info) => info.language === lang);

Expand Down Expand Up @@ -83,9 +96,14 @@ export class TasklistStateDTO {
relevant_topics: dataset.datasetTopics?.length > 0 ? TaskStatus.Completed : TaskStatus.NotStarted
};

const dimensionsComplete = every(dimensions, (dim) => dim.status === TaskStatus.Completed);
const metadataComplete = every(dto.metadata, (status) => status === TaskStatus.Completed);

// TODO: export should check for dimensionsComplete as well

Check warning on line 102 in src/dtos/tasklist-state-dto.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unexpected 'todo' comment: 'TODO: export should check for...'
// TODO: import should check export complete and nothing was updated since the export (needs audit table)

Check warning on line 103 in src/dtos/tasklist-state-dto.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unexpected 'todo' comment: 'TODO: import should check export...'
dto.translation = {
export: TaskStatus.NotImplemented,
import: TaskStatus.NotImplemented
export: metadataComplete ? TaskStatus.Available : TaskStatus.CannotStart,
import: metadataComplete ? TasklistStateDTO.translationStatus(dataset) : TaskStatus.CannotStart
};

dto.publishing = {
Expand Down
7 changes: 7 additions & 0 deletions src/dtos/translations-dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class TranslationDTO {
type: string;
key: string;
id?: string;
english?: string;
cymraeg?: string;
}
3 changes: 3 additions & 0 deletions src/enums/task-status.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export enum TaskStatus {
CannotStart = 'cannot_start',
Available = 'available',
NotStarted = 'not_started',
Incomplete = 'incomplete',
Completed = 'completed',
NotImplemented = 'not_implemented'
}
63 changes: 56 additions & 7 deletions src/repositories/dataset.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DeepPartial, FindOneOptions, FindOptionsRelations } from 'typeorm';
import { FindOneOptions, FindOptionsRelations } from 'typeorm';
import { has } from 'lodash';

import { dataSource } from '../db/data-source';
Expand All @@ -13,6 +13,8 @@ import { DatasetProviderDTO } from '../dtos/dataset-provider-dto';
import { DatasetProvider } from '../entities/dataset/dataset-provider';
import { DatasetTopic } from '../entities/dataset/dataset-topic';
import { Team } from '../entities/user/team';
import { TranslationDTO } from '../dtos/translations-dto';
import { DimensionInfo } from '../entities/dataset/dimension-info';

const defaultRelations: FindOptionsRelations<Dataset> = {
createdBy: true,
Expand Down Expand Up @@ -60,15 +62,19 @@ export const DatasetRepository = dataSource.getRepository(Dataset).extend({
await this.delete({ id });
},

async createWithTitle(user: User, language?: string, title?: string): Promise<Dataset> {
async createWithTitle(user: User, language: Locale, title: string): Promise<Dataset> {
logger.debug(`Creating new Dataset...`);
const dataset = await this.create({ createdBy: user }).save();
const altLang = language.includes('en') ? Locale.WelshGb : Locale.EnglishGb;

if (language && title) {
logger.debug(`Creating new DatasetInfo with language "${language}" and title "${title}"...`);
const datasetInfo = await dataSource.getRepository(DatasetInfo).create({ dataset, language, title }).save();
dataset.datasetInfo = [datasetInfo];
}
logger.debug(`Creating new DatasetInfo with language "${language}" and title "${title}"...`);
const datasetInfo = await dataSource.getRepository(DatasetInfo).create({ dataset, language, title }).save();
const altLangDatasetInfo = await dataSource
.getRepository(DatasetInfo)
.create({ dataset, language: altLang })
.save();

dataset.datasetInfo = [datasetInfo, altLangDatasetInfo];

return this.getById(dataset.id);
},
Expand Down Expand Up @@ -183,6 +189,49 @@ export const DatasetRepository = dataSource.getRepository(Dataset).extend({
const team = await dataSource.getRepository(Team).findOneByOrFail({ id: teamId });
dataset.team = team;
await dataset.save();
return this.getById(datasetId);
},

async updateTranslations(datasetId: string, translations: TranslationDTO[]): Promise<Dataset> {
const dataset = await this.findOneOrFail({ where: { id: datasetId } });
const dimensionInfoRepo = dataSource.getRepository(DimensionInfo);
const infoRepo = dataSource.getRepository(DatasetInfo);

const dimensionTranslations = translations.filter((t) => t.type === 'dimension');

logger.debug(`Updating dimension names...`);

for (const row of dimensionTranslations) {
const englishDimInfo = await dimensionInfoRepo.findOneByOrFail({ id: row.id, language: Locale.EnglishGb });
englishDimInfo.name = row.english || '';
await englishDimInfo.save();

const welshDimInfo = await dimensionInfoRepo.findOneByOrFail({ id: row.id, language: Locale.WelshGb });
welshDimInfo.name = row.cymraeg || '';
await welshDimInfo.save();
}

const metaTranslations = translations.filter((t) => t.type === 'metadata');

logger.debug(`Updating metadata...`);

const englishInfo =
(await infoRepo.findOneBy({ dataset, language: Locale.EnglishGb })) ||
infoRepo.create({ dataset, language: Locale.EnglishGb });

const welshInfo =
(await infoRepo.findOneBy({ dataset, language: Locale.WelshGb })) ||
infoRepo.create({ ...englishInfo, language: Locale.WelshGb });

metaTranslations.forEach((row) => {
const metaKey = row.key as 'title' | 'description' | 'collection' | 'quality' | 'roundingDescription';
englishInfo[metaKey] = row.english || '';
welshInfo[metaKey] = row.cymraeg || '';
});

await englishInfo.save();
await welshInfo.save();

return this.getById(datasetId);
}
});
3 changes: 3 additions & 0 deletions src/resources/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"publish_at": {
"invalid": "Publish at is missing or invalid",
"in_past": "Publish at cannot be in the past"
},
"translation_file": {
"invalid": "Uploaded translation file keys do not match the exported file"
}
},
"dimension_info": {
Expand Down
3 changes: 2 additions & 1 deletion src/route/dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ router.post('/', jsonParser, async (req: Request, res: Response, next: NextFunct
}

try {
const dataset = await DatasetRepository.createWithTitle(req.user as User, req.language, req.body.title);
const language = req.language as Locale;
const dataset = await DatasetRepository.createWithTitle(req.user as User, language, req.body.title);
logger.info(`Dataset created with id: ${dataset.id}`);
res.status(201);
res.json(DatasetDTO.fromDataset(dataset));
Expand Down
Loading

0 comments on commit 2c4ed2b

Please sign in to comment.