Add translation for product names (#74)

This commit is contained in:
Niklas Fondberg
2021-10-26 10:08:25 +02:00
committed by GitHub
parent ac5be19649
commit 56ad07edf8
5 changed files with 127 additions and 4 deletions
+5
View File
@@ -185,6 +185,11 @@ Resources:
Action: Action:
- s3:* - s3:*
Resource: !Sub arn:aws:s3:::${UploadBucket} Resource: !Sub arn:aws:s3:::${UploadBucket}
- Effect: Allow
Action:
- 'comprehend:DetectDominantLanguage'
- 'translate:TranslateText'
Resource: '*'
# A role for the containers # A role for the containers
TaskRole: TaskRole:
-1
View File
@@ -25,7 +25,6 @@ export async function sendMessage(
body: string, body: string,
queueUrl: string, queueUrl: string,
): Promise<SendMessageCommandOutput | undefined> { ): Promise<SendMessageCommandOutput | undefined> {
console.log('Senfing', body);
const client = new SQSClient({ region: 'eu-west-1' }); const client = new SQSClient({ region: 'eu-west-1' });
const params: SendMessageCommandInput = { const params: SendMessageCommandInput = {
+12 -1
View File
@@ -28,12 +28,15 @@ import {
} from './utils'; } from './utils';
import { UserInputError } from 'apollo-server'; import { UserInputError } from 'apollo-server';
import { sendPathChangedCmd } from '../bernard/client'; import { sendPathChangedCmd } from '../bernard/client';
import { TextsAPI } from './texts-api';
const MINUTE = 60; const MINUTE = 60;
export class ProductAPI extends BaseSQLDataSource { export class ProductAPI extends BaseSQLDataSource {
constructor(config) { textsApi: TextsAPI;
constructor(config, textsApi) {
super(config); super(config);
this.textsApi = textsApi;
} }
// async getMaterial(printId: number): Promise<any> { // async getMaterial(printId: number): Promise<any> {
@@ -384,6 +387,14 @@ export class ProductAPI extends BaseSQLDataSource {
sendPathChangedCmd(oldProd.path, uniquePath); sendPathChangedCmd(oldProd.path, uniquePath);
} }
if (oldProd.fields.name !== info.name) {
await this.textsApi.translateProductName(
info.name,
oldProd.path,
uniquePath,
);
}
const promises = []; const promises = [];
promises.push( promises.push(
this.knex this.knex
+106
View File
@@ -0,0 +1,106 @@
import { SQLDataSource } from 'datasource-sql';
import { TranslateInput, translateText } from '../aws/translate';
import { Locale } from '../types/market-locale-types';
import { MarketLocaleAPI } from './market-locale-api';
const MINUTE = 60;
// TODO: perhaps rename to MarketLocale API and add market_locales and locales here.
export class TextsAPI extends SQLDataSource {
marketLocaleApi: MarketLocaleAPI;
constructor(config, marketLocaleApi: MarketLocaleAPI) {
super(config);
this.marketLocaleApi = marketLocaleApi;
}
async translateProductName(name: string, oldPath, newPath): Promise<void> {
// Check if we have an entry already
const textKey = await this.upsertTextId(newPath, oldPath);
const locales = await this.marketLocaleApi.getLocales();
for (let i = 0; i < locales.length; i++) {
let langCode = this.getLanguageCode(locales[i]);
// If we have a fallback locale we skip translating
if (locales[i].fallbackId) {
continue;
}
const input: TranslateInput = {
text: name,
targetLanguageCode: langCode,
};
const translated = await translateText(input);
await this.upsertTextDataEntry(textKey.textid, translated, locales[i].id);
}
}
/**
* Upsert translated entry to the i18n-texts_data table
* @param text The translated text to insert
* @param localeId The id of the locale
*/
private async upsertTextDataEntry(
textId: number,
text: string,
localeId: number,
) {
// Check if we have an entry already
const textDataEntry = await this.knex
.select('*')
.from('i18n-texts_data')
.where({ textid: textId, locale_id: localeId })
.first();
if (textDataEntry) {
// Update existing entry
await this.knex('i18n-texts_data')
.where({ textid: textId, locale_id: localeId })
.update({ text: text });
} else {
//Insert new entry
await this.knex('i18n-texts_data').insert({
text: text,
textid: textId,
locale_id: localeId,
});
}
}
private getLanguageCode(locale: Locale) {
let langCode = locale.value.substr(0, 2);
return langCode == 'nn' ? 'no' : langCode;
}
/**
* Upsert translated entry to the i18n-texts table
* @param newKey the new name of the text key
* @param localeId the old name of the text key
*/
private async upsertTextId(newKey: string, oldKey: string) {
let textEntry = await this.knex
.select('*')
.from('i18n-texts')
.where({ name: oldKey })
.first();
let textId = textEntry?.textid;
// No entry, create one
if (!textId) {
const res = await this.knex('i18n-texts')
.insert({ name: newKey, category: 'productTitles' })
.returning('*');
textEntry = res[0];
}
// Update table if different
if (oldKey !== newKey) {
await this.knex
.table('i18n-texts')
.update({ name: newKey })
.where({ name: oldKey });
}
return textEntry;
}
}
+4 -2
View File
@@ -18,6 +18,7 @@ import { InteriorAPI } from './datasources/interior-api';
import { ClaimVerifyResult, verifyToken } from './cognito/cognito-client'; import { ClaimVerifyResult, verifyToken } from './cognito/cognito-client';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { InteriorsLambdaAPI } from './datasources/interiors-lambda-api'; import { InteriorsLambdaAPI } from './datasources/interiors-lambda-api';
import { TextsAPI } from './datasources/texts-api';
const path = require('path'); const path = require('path');
const typeDefs = readFileSync( const typeDefs = readFileSync(
path.join(__dirname, './schema.graphql'), path.join(__dirname, './schema.graphql'),
@@ -27,15 +28,16 @@ const typeDefs = readFileSync(
const knexConfig = knexStringcase(dbConfig); const knexConfig = knexStringcase(dbConfig);
// set up any dataSources our resolvers need // set up any dataSources our resolvers need
const marketLocaleApi = new MarketLocaleAPI(knexConfig);
const textsApi = new TextsAPI(knexConfig, marketLocaleApi);
const categoryApi = new CategoryAPI(knexConfig); const categoryApi = new CategoryAPI(knexConfig);
const designerApi = new DesignerAPI(knexConfig); const designerApi = new DesignerAPI(knexConfig);
const imageServerApi = new ImageServerApi(); const imageServerApi = new ImageServerApi();
const interiorsLambdaApi = new InteriorsLambdaAPI(); const interiorsLambdaApi = new InteriorsLambdaAPI();
const interiorApi = new InteriorAPI(knexConfig, imageServerApi); const interiorApi = new InteriorAPI(knexConfig, imageServerApi);
const keywordApi = new KeywordAPI(knexConfig); const keywordApi = new KeywordAPI(knexConfig);
const marketLocaleApi = new MarketLocaleAPI(knexConfig);
const orderApi = new OrderAPI(knexConfig); const orderApi = new OrderAPI(knexConfig);
const productApi = new ProductAPI(knexConfig); const productApi = new ProductAPI(knexConfig, textsApi);
const dataSources = () => ({ const dataSources = () => ({
categoryApi, categoryApi,