diff --git a/src/api/parole/services/__tests__/parole.test.js b/src/api/parole/services/__tests__/parole.test.js index a435348..456e2dc 100644 --- a/src/api/parole/services/__tests__/parole.test.js +++ b/src/api/parole/services/__tests__/parole.test.js @@ -57,4 +57,28 @@ describe('translateLyrics', () => { expect(result.anglais).toContain('traduit-EN'); expect(result.espagnol).toBeUndefined(); }); + + it('traduit les langues africaines ajoutées, sans appeler DeepL pour le yoruba', async () => { + global.fetch = vi.fn(async (_url, options) => { + const {target_lang: target} = JSON.parse(options.body); + return fakeDeeplResponse(`traduit-${target}`); + }); + + const strapi = { + contentType: vi.fn(() => ({uid: 'api::parole.parole', kind: 'collectionType'})), + log: {error: vi.fn()} + }; + const service = createService({strapi}); + const result = await service.translateLyrics('Bonjour le monde'); + + expect(result.swahili).toContain('traduit-SW'); + expect(result.lingala).toContain('traduit-LN'); + expect(result.wolof).toContain('traduit-WO'); + expect(result.hausa).toContain('traduit-HA'); + expect(result.yoruba).toBeUndefined(); + + const calledTargets = global.fetch.mock.calls.map(([, options]) => JSON.parse(options.body).target_lang); + expect(calledTargets).not.toContain('YO'); + expect(calledTargets).not.toContain(undefined); + }); }); diff --git a/src/api/parole/services/parole.js b/src/api/parole/services/parole.js index 4dce3f9..a7fe9ce 100644 --- a/src/api/parole/services/parole.js +++ b/src/api/parole/services/parole.js @@ -6,6 +6,21 @@ const { ApplicationError } = require('@strapi/utils').errors; const LANG_MAP = { fr: { field: 'francais', targetLang: 'fr', userPrompt: 'Tradui an fransé' }, + // Pas de code DeepL pour le yoruba : traduction manuelle uniquement. + yo: { field: 'yoruba', targetLang: 'yo', userPrompt: 'Translate to Yoruba' }, + ln: { field: 'lingala', targetLang: 'ln', userPrompt: 'Translate to Lingala', deeplTarget: 'LN', suffix: '\n\n (DeepL)' }, + wo: { field: 'wolof', targetLang: 'wo', userPrompt: 'Translate to Wolof', deeplTarget: 'WO', suffix: '\n\n (DeepL)' }, + sw: { field: 'swahili', targetLang: 'sw', userPrompt: 'Translate to Swahili', deeplTarget: 'SW', suffix: '\n\n (DeepL)' }, + ha: { field: 'hausa', targetLang: 'ha', userPrompt: 'Translate to Hausa', deeplTarget: 'HA', suffix: '\n\n (DeepL)' }, + ar: { field: 'arabe', targetLang: 'ar', userPrompt: 'Translate to Arabic', deeplTarget: 'AR', suffix: '\n\n (DeepL)' }, + om: { field: 'oromo', targetLang: 'om', userPrompt: 'Translate to Oromo', deeplTarget: 'OM', suffix: '\n\n (DeepL)' }, + ig: { field: 'igbo', targetLang: 'ig', userPrompt: 'Translate to Igbo', deeplTarget: 'IG', suffix: '\n\n (DeepL)' }, + zu: { field: 'zoulou', targetLang: 'zu', userPrompt: 'Translate to Zulu', deeplTarget: 'ZU', suffix: '\n\n (DeepL)' }, + mg: { field: 'malgache', targetLang: 'mg', userPrompt: 'Translate to Malagasy', deeplTarget: 'MG', suffix: '\n\n (DeepL)' }, + xh: { field: 'xhosa', targetLang: 'xh', userPrompt: 'Translate to Xhosa', deeplTarget: 'XH', suffix: '\n\n (DeepL)' }, + tn: { field: 'tswana', targetLang: 'tn', userPrompt: 'Translate to Tswana', deeplTarget: 'TN', suffix: '\n\n (DeepL)' }, + ts: { field: 'tsonga', targetLang: 'ts', userPrompt: 'Translate to Tsonga', deeplTarget: 'TS', suffix: '\n\n (DeepL)' }, + st: { field: 'sesotho', targetLang: 'st', userPrompt: 'Translate to Sesotho', deeplTarget: 'ST', suffix: '\n\n (DeepL)' }, ja: { field: 'japonais', targetLang: 'ja', userPrompt: '日本語に翻訳して', deeplTarget: 'JA', suffix: '\n\n (DeepLによる翻訳)' }, ko: { field: 'coreen', targetLang: 'ko', userPrompt: '한국어로 번역해줘', deeplTarget: 'KO', suffix: '\n\n (DeepL 번역)' }, en: { field: 'anglais', targetLang: 'en', userPrompt: 'Translate to English', deeplTarget: 'EN', suffix: '\n\n (Translated by DeepL)' }, @@ -16,6 +31,8 @@ const LANG_MAP = { }; const ALL_LANGS = Object.keys(LANG_MAP); +// Langues suivies (schéma + export) mais sans traduction automatique DeepL. +const NO_AUTO_TRANSLATE = new Set(['fr', 'yo']); function stripMarkdown(text) { if (!text) return ''; @@ -88,7 +105,7 @@ module.exports = createCoreService('api::parole.parole', ({strapi}) => ({ const result = { francais: parolesFR }; for (const lang of ALL_LANGS) { - if (lang === 'fr') continue; + if (NO_AUTO_TRANSLATE.has(lang)) continue; const { field, deeplTarget, suffix } = LANG_MAP[lang]; try { const translated = await this.translate('FR', deeplTarget, parolesFR); @@ -203,7 +220,7 @@ module.exports = createCoreService('api::parole.parole', ({strapi}) => ({ async bulkTranslateMissing() { const TARGET_LANGS = ALL_LANGS - .filter(lang => lang !== 'fr') + .filter(lang => !NO_AUTO_TRANSLATE.has(lang)) .map(lang => ({ lang, ...LANG_MAP[lang] })); const pageSize = 100; diff --git a/src/components/trad/traductions.json b/src/components/trad/traductions.json index 13e2872..0d06224 100644 --- a/src/components/trad/traductions.json +++ b/src/components/trad/traductions.json @@ -10,6 +10,48 @@ "francais": { "type": "richtext" }, + "yoruba": { + "type": "richtext" + }, + "lingala": { + "type": "richtext" + }, + "wolof": { + "type": "richtext" + }, + "swahili": { + "type": "richtext" + }, + "hausa": { + "type": "richtext" + }, + "arabe": { + "type": "richtext" + }, + "oromo": { + "type": "richtext" + }, + "igbo": { + "type": "richtext" + }, + "zoulou": { + "type": "richtext" + }, + "malgache": { + "type": "richtext" + }, + "xhosa": { + "type": "richtext" + }, + "tswana": { + "type": "richtext" + }, + "tsonga": { + "type": "richtext" + }, + "sesotho": { + "type": "richtext" + }, "japonais": { "type": "richtext" }, diff --git a/types/generated/components.d.ts b/types/generated/components.d.ts index 5adc3cc..8bcd2de 100644 --- a/types/generated/components.d.ts +++ b/types/generated/components.d.ts @@ -109,12 +109,26 @@ export interface TradTraductions extends Struct.ComponentSchema { attributes: { allemand: Schema.Attribute.RichText; anglais: Schema.Attribute.RichText; + arabe: Schema.Attribute.RichText; coreen: Schema.Attribute.RichText; espagnol: Schema.Attribute.RichText; francais: Schema.Attribute.RichText; + hausa: Schema.Attribute.RichText; + igbo: Schema.Attribute.RichText; italien: Schema.Attribute.RichText; japonais: Schema.Attribute.RichText; + lingala: Schema.Attribute.RichText; + malgache: Schema.Attribute.RichText; + oromo: Schema.Attribute.RichText; portugais: Schema.Attribute.RichText; + sesotho: Schema.Attribute.RichText; + swahili: Schema.Attribute.RichText; + tsonga: Schema.Attribute.RichText; + tswana: Schema.Attribute.RichText; + wolof: Schema.Attribute.RichText; + xhosa: Schema.Attribute.RichText; + yoruba: Schema.Attribute.RichText; + zoulou: Schema.Attribute.RichText; }; }