feat(translation): Add multi-language support for document translations.

This commit is contained in:
Philipp Kunz 2024-12-02 12:46:28 +01:00
parent c8b102e798
commit d59734fb7c
11 changed files with 121 additions and 21 deletions

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## 2024-12-02 - 1.3.0 - feat(translation)
Add multi-language support for document translations.
- Implemented translation interface for document labels.
- Added Spanish translations alongside existing English and German.
- Updated content invoice, page header, and page footer elements to utilize language-specific translations.
## 2024-12-01 - 1.2.0 - feat(core) ## 2024-12-01 - 1.2.0 - feat(core)
Enhance document generation capabilities with improved modular structure and extended translation support. Enhance document generation capabilities with improved modular structure and extended translation support.

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-document', name: '@design.estate/dees-document',
version: '1.2.0', version: '1.3.0',
description: 'A comprehensive tool for dynamically generating and rendering business documents like invoices using modern web technologies.' description: 'A comprehensive tool for dynamically generating and rendering business documents like invoices using modern web technologies.'
} }

View File

@ -1,4 +1,19 @@
export interface IDeDocumentTranslations { export interface IDeDocumentTranslations {
"invoice": string; address: string;
"quantity": string; bankConnection: string;
contactInfo: string;
description: string;
invoice: string;
itemPos: string;
quantity: string;
registrationInfo: string;
reverseVatNote: string;
totalNetPrice: string;
unitNetPrice: string;
unitType: string;
yourCustomerId: string;
yourVatId: string;
continuesOnPage: string;
finalPageStatement: string;
page: string;
} }

View File

@ -5,18 +5,69 @@ type TTranslationImplementation = {
} }
export const EN_translations: TTranslationImplementation = { export const EN_translations: TTranslationImplementation = {
address: 'Address',
bankConnection: 'Bank Connection',
contactInfo: 'Contact Info',
description: 'Description',
invoice: 'Invoice', invoice: 'Invoice',
itemPos: 'Item Pos.',
quantity: 'Quantity', quantity: 'Quantity',
registrationInfo: 'Registration Info',
reverseVatNote: 'VAT arises on a reverse charge basis and is payable by the customer.',
totalNetPrice: 'Total Net Price',
unitNetPrice: 'Unit Net Price',
unitType: 'Unit Type',
yourCustomerId: 'Your Customer ID:',
yourVatId: 'Your vat id on file:',
continuesOnPage: 'Continues on page',
finalPageStatement: 'This is the final page of this document.',
page: 'Page',
}; };
export const DE_translations: TTranslationImplementation = { export const DE_translations: TTranslationImplementation = {
address: 'Adresse',
bankConnection: 'Bankverbindung',
contactInfo: 'Kontaktinformationen',
description: 'Beschreibung',
invoice: 'Rechnung', invoice: 'Rechnung',
itemPos: 'Pos.',
quantity: 'Anzahl', quantity: 'Anzahl',
registrationInfo: 'HRA/HRB Info',
reverseVatNote: 'Umkehr der Umsatzsteuerpflicht: Der Rechnungsempfänger ist für die korrekte Abrechnung der Umsatzsteuer zuständig.',
totalNetPrice: 'Nettopreis Summe',
unitNetPrice: 'Nettopreis',
unitType: 'Einheit',
yourCustomerId: 'Ihre Kundennummer:',
yourVatId: 'Ihre Umsatzsteuer-ID:',
continuesOnPage: 'Fortsetzung auf Seite',
finalPageStatement: 'Diese ist die letzte Seite einer Dokumente.',
page: 'Seite',
};
export const ES_translations: TTranslationImplementation = {
address: 'Dirección',
bankConnection: 'Conexión bancaria',
contactInfo: 'Información de contacto',
description: 'Descripción',
invoice: 'Factura',
itemPos: 'Pos.',
quantity: 'Cantidad',
registrationInfo: 'Información de registro',
reverseVatNote: 'La declaración de IVA se aplica en base a la factura de venta, y se paga por el cliente.',
totalNetPrice: 'Precio total neto',
unitNetPrice: 'Precio unitario neto',
unitType: 'Tipo de unidad',
yourCustomerId: 'Su número de cliente:',
yourVatId: 'Su ID de IVA:',
continuesOnPage: 'Continues on page',
finalPageStatement: 'This is the final page of this document.',
page: 'Page',
}; };
export const languageCodeMap = { export const languageCodeMap = {
'DE': DE_translations, 'DE': DE_translations,
'EN': EN_translations, 'EN': EN_translations,
'ES': ES_translations,
}; };
export type TLanguageCode = keyof typeof languageCodeMap; export type TLanguageCode = keyof typeof languageCodeMap;

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-document', name: '@design.estate/dees-document',
version: '1.2.0', version: '1.3.0',
description: 'A comprehensive tool for dynamically generating and rendering business documents like invoices using modern web technologies.' description: 'A comprehensive tool for dynamically generating and rendering business documents like invoices using modern web technologies.'
} }

View File

@ -16,7 +16,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
import * as shared from '../../ts/shared/index.js'; import * as shared from '../../ts/shared/index.js';
import * as interfaces from '../../ts/interfaces/index.js';
declare global { declare global {
@ -45,6 +45,12 @@ export class DeContentInvoice extends DeesElement {
}) })
public letterData: plugins.tsclass.business.ILetter; public letterData: plugins.tsclass.business.ILetter;
@property({
type: Object,
reflect: true,
})
public documentSettings: interfaces.IDocumentSettings;
constructor() { constructor() {
super(); super();
domtools.DomTools.setupDomTools(); domtools.DomTools.setupDomTools();
@ -275,12 +281,12 @@ export class DeContentInvoice extends DeesElement {
</style> </style>
<div>We hereby invoice products and services provided to you by Lossless GmbH:</div> <div>We hereby invoice products and services provided to you by Lossless GmbH:</div>
<div class="grid topLine dataHeader"> <div class="grid topLine dataHeader">
<div class="lineItem">Item Pos.</div> <div class="lineItem">${shared.translation.translate(this.documentSettings.languageCode, 'itemPos', 'Item Pos.')}</div>
<div class="lineItem">${shared.translation.translate('DE', 'description', 'Description')}</div> <div class="lineItem">${shared.translation.translate(this.documentSettings.languageCode, 'description', 'Description')}</div>
<div class="lineItem">${shared.translation.translate('DE', 'quantity', 'Quantity')}</div> <div class="lineItem">${shared.translation.translate(this.documentSettings.languageCode, 'quantity', 'Quantity')}</div>
<div class="lineItem">Unit Type</div> <div class="lineItem">${shared.translation.translate(this.documentSettings.languageCode, 'unitType', 'Unit Type')}</div>
<div class="lineItem">Unit Net Price</div> <div class="lineItem">${shared.translation.translate(this.documentSettings.languageCode, 'unitNetPrice', 'Unit Net Price')}</div>
<div class="lineItem">Total Net Price</div> <div class="lineItem">${shared.translation.translate(this.documentSettings.languageCode, 'totalNetPrice', 'Total Net Price')}</div>
</div> </div>
${(() => { ${(() => {
let counter = 1; let counter = 1;
@ -329,7 +335,7 @@ export class DeContentInvoice extends DeesElement {
${this.letterData?.content.invoiceData.reverseCharge ${this.letterData?.content.invoiceData.reverseCharge
? html` ? html`
<div class="taxNote"> <div class="taxNote">
VAT arises on a reverse charge basis and is payable by the customer. ${shared.translation.translate(this.documentSettings.languageCode, 'reverseVatNote', 'VAT arises on a reverse charge basis and is payable by the customer.')}
</div> </div>
` `
: ``} : ``}

View File

@ -146,6 +146,7 @@ export class DeDocument extends DeesElement {
// lets append the content // lets append the content
const content: DeContentInvoice = new DeContentInvoice(); const content: DeContentInvoice = new DeContentInvoice();
content.letterData = this.letterData; content.letterData = this.letterData;
content.documentSettings = this.documentSettings;
document.body.appendChild(content); document.body.appendChild(content);
await domtools.convenience.smartdelay.delayFor(0); await domtools.convenience.smartdelay.delayFor(0);
@ -158,6 +159,7 @@ export class DeDocument extends DeesElement {
const newPage = new DePage(); const newPage = new DePage();
newPage.printMode = this.printMode; newPage.printMode = this.printMode;
newPage.letterData = this.letterData; newPage.letterData = this.letterData;
newPage.documentSettings = this.documentSettings;
pages.push(newPage); pages.push(newPage);
newPage.pageNumber = pageCounter; newPage.pageNumber = pageCounter;
newPage.append(currentContent); newPage.append(currentContent);

View File

@ -127,6 +127,7 @@ export class DePage extends DeesElement {
? html` ? html`
<dedocument-pageheader <dedocument-pageheader
.letterData=${this.letterData} .letterData=${this.letterData}
.documentSettings=${this.documentSettings}
.pageNumber="${this.pageNumber}" .pageNumber="${this.pageNumber}"
.pageTotalNumber="${this.pageTotalNumber}" .pageTotalNumber="${this.pageTotalNumber}"
></dedocument-pageheader> ></dedocument-pageheader>
@ -137,20 +138,23 @@ export class DePage extends DeesElement {
<dedocument-letterheader <dedocument-letterheader
.pageNumber="${this.pageNumber}" .pageNumber="${this.pageNumber}"
.letterData=${this.letterData} .letterData=${this.letterData}
.documentSettings=${this.documentSettings}
.pageTotalNumber="${this.pageTotalNumber}" .pageTotalNumber="${this.pageTotalNumber}"
></dedocument-letterheader> ></dedocument-letterheader>
` `
: html``} : html``}
<dedocument-pagecontent <dedocument-pagecontent
.letterData=${this.letterData}
.documentSettings=${this.documentSettings}
.pageNumber="${this.pageNumber}" .pageNumber="${this.pageNumber}"
.pageTotalNumber="${this.pageTotalNumber}" .pageTotalNumber="${this.pageTotalNumber}"
.letterData=${this.letterData}
><slot></slot ><slot></slot
></dedocument-pagecontent> ></dedocument-pagecontent>
${this.documentSettings.enableDefaultFooter ${this.documentSettings.enableDefaultFooter
? html` ? html`
<dedocument-pagefooter <dedocument-pagefooter
.letterData=${this.letterData} .letterData=${this.letterData}
.documentSettings=${this.documentSettings}
.pageNumber="${this.pageNumber}" .pageNumber="${this.pageNumber}"
.pageTotalNumber="${this.pageTotalNumber}" .pageTotalNumber="${this.pageTotalNumber}"
></dedocument-pagefooter> ></dedocument-pagefooter>

View File

@ -7,8 +7,10 @@ import {
css, css,
cssManager, cssManager,
unsafeCSS, unsafeCSS,
domtools,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import * as interfaces from '../../ts/interfaces/index.js';
import * as shared from '../../ts/shared/index.js'; import * as shared from '../../ts/shared/index.js';
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';
@ -30,6 +32,12 @@ export class DePageFooter extends DeesElement {
}) })
letterData: tsclass.business.ILetter; letterData: tsclass.business.ILetter;
@property({
type: Object,
reflect: true,
})
documentSettings: interfaces.IDocumentSettings;
@property({ @property({
type: Number type: Number
}) })
@ -96,26 +104,26 @@ export class DePageFooter extends DeesElement {
return html` return html`
<div class="bottomstripe"> <div class="bottomstripe">
<div> <div>
<strong>Address:</strong><br /> <strong>${shared.translation.translate(this.documentSettings.languageCode, 'address', 'Address')}:</strong><br />
${this.letterData.from.name}<br /> ${this.letterData.from.name}<br />
${this.letterData.from.address.streetName} ${this.letterData.from.address.houseNumber}<br /> ${this.letterData.from.address.streetName} ${this.letterData.from.address.houseNumber}<br />
${this.letterData.from.address.postalCode} ${this.letterData.from.address.city}<br /> ${this.letterData.from.address.postalCode} ${this.letterData.from.address.city}<br />
${this.letterData.from.address.country} ${this.letterData.from.address.country}
</div> </div>
<div> <div>
<strong>Registration Info:</strong><br /> <strong>${shared.translation.translate(this.documentSettings.languageCode, 'registrationInfo', 'Registration Info')}:</strong><br />
Amtsgericht Bremen<br /> Amtsgericht Bremen<br />
<i>reg-#:</i> HRB 35230 HB<br /> <i>reg-#:</i> HRB 35230 HB<br />
<i>vat-id:</i> ${this.letterData.from.vatId} <i>vat-id:</i> ${this.letterData.from.vatId}
</div> </div>
<div> <div>
<strong>Contact Info:</strong><br /> <strong>${shared.translation.translate(this.documentSettings.languageCode, 'contactInfo', 'Contact Info')}:</strong><br />
<i>email:</i> ${this.letterData.from.email}<br /> <i>email:</i> ${this.letterData.from.email}<br />
<i>phone:</i> ${this.letterData.from.phone}<br /> <i>phone:</i> ${this.letterData.from.phone}<br />
<i>fax:</i> ${this.letterData.from.fax} <i>fax:</i> ${this.letterData.from.fax}
</div> </div>
<div> <div>
<strong>Bank Connection:</strong><br /> <strong>${shared.translation.translate(this.documentSettings.languageCode, 'bankConnection', 'Bank Connection')}:</strong><br />
<i>beneficiary:</i> ${this.letterData?.from?.name}<br /> <i>beneficiary:</i> ${this.letterData?.from?.name}<br />
<i>institution:</i> ${this.letterData?.from?.sepaConnection?.institution}<br /> <i>institution:</i> ${this.letterData?.from?.sepaConnection?.institution}<br />
<i>iban:</i> ${this.letterData?.from?.sepaConnection?.iban}<br /> <i>iban:</i> ${this.letterData?.from?.sepaConnection?.iban}<br />

View File

@ -7,8 +7,10 @@ import {
css, css,
cssManager, cssManager,
unsafeCSS, unsafeCSS,
domtools
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import * as interfaces from '../../ts/interfaces/index.js';
import * as shared from '../../ts/shared/index.js'; import * as shared from '../../ts/shared/index.js';
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';
@ -30,6 +32,12 @@ export class DePageHeader extends DeesElement {
}) })
public letterData: tsclass.business.ILetter = null; public letterData: tsclass.business.ILetter = null;
@property({
type: Object,
reflect: true,
})
documentSettings: interfaces.IDocumentSettings;
@property({ @property({
type: Number, type: Number,
}) })

View File

@ -3,7 +3,6 @@ import * as interfaces from '../../ts/interfaces/index.js';
import { DeesElement, css, cssManager, customElement, html } from '@design.estate/dees-element'; import { DeesElement, css, cssManager, customElement, html } from '@design.estate/dees-element';
import { demoFunc } from './viewer.demo.js'; import { demoFunc } from './viewer.demo.js';
import { defaultDocumentSettings } from './document.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@ -19,7 +18,7 @@ export class DeDocumentViewer extends DeesElement {
// INSTANCE // INSTANCE
public letterData: plugins.tsclass.business.ILetter = null; public letterData: plugins.tsclass.business.ILetter = null;
public documentSettings: interfaces.IDocumentSettings = defaultDocumentSettings; public documentSettings: interfaces.IDocumentSettings;
public static styles = [ public static styles = [
cssManager.defaultStyles, cssManager.defaultStyles,