Add i18n service to query XML files (#2503)
* Add i18n service to query XML files * Update changelog --------- Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com>
This commit is contained in:
parent
c9878c9050
commit
29028a81f5
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added a chart to the account detail dialog
|
- Added a chart to the account detail dialog
|
||||||
|
- Added an `i18n` service to query `messages.*.xlf` files on the server
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import * as fs from 'fs';
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { environment } from '@ghostfolio/api/environments/environment';
|
import { environment } from '@ghostfolio/api/environments/environment';
|
||||||
|
import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service';
|
||||||
import {
|
import {
|
||||||
DEFAULT_LANGUAGE_CODE,
|
DEFAULT_LANGUAGE_CODE,
|
||||||
DEFAULT_ROOT_URL,
|
DEFAULT_ROOT_URL,
|
||||||
@ -11,20 +12,11 @@ import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper';
|
|||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
|
|
||||||
const descriptions = {
|
|
||||||
de: 'Mit dem Finanz-Dashboard Ghostfolio können Sie Ihr Vermögen in Form von Aktien, ETFs oder Kryptowährungen verteilt über mehrere Finanzinstitute überwachen.',
|
|
||||||
en: 'Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies across multiple platforms.',
|
|
||||||
es: 'Ghostfolio es un dashboard de finanzas personales para hacer un seguimiento de tus activos como acciones, ETFs o criptodivisas a través de múltiples plataformas.',
|
|
||||||
fr: 'Ghostfolio est un dashboard de finances personnelles qui permet de suivre vos actifs comme les actions, les ETF ou les crypto-monnaies sur plusieurs plateformes.',
|
|
||||||
it: 'Ghostfolio è un dashboard di finanza personale per tenere traccia delle vostre attività come azioni, ETF o criptovalute su più piattaforme.',
|
|
||||||
nl: 'Ghostfolio is een persoonlijk financieel dashboard om uw activa zoals aandelen, ETF’s of cryptocurrencies over meerdere platforms bij te houden.',
|
|
||||||
pt: 'Ghostfolio é um dashboard de finanças pessoais para acompanhar os seus activos como acções, ETFs ou criptomoedas em múltiplas plataformas.',
|
|
||||||
tr: 'Ghostfolio, hisse senetleri, ETF’ler veya kripto para birimleri gibi varlıklarınızı birden fazla platformda takip etmenizi sağlayan bir kişisel finans panosudur.'
|
|
||||||
};
|
|
||||||
|
|
||||||
const title = 'Ghostfolio – Open Source Wealth Management Software';
|
const title = 'Ghostfolio – Open Source Wealth Management Software';
|
||||||
const titleShort = 'Ghostfolio';
|
const titleShort = 'Ghostfolio';
|
||||||
|
|
||||||
|
const i18nService = new I18nService();
|
||||||
|
|
||||||
let indexHtmlMap: { [languageCode: string]: string } = {};
|
let indexHtmlMap: { [languageCode: string]: string } = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -130,7 +122,10 @@ export const HtmlTemplateMiddleware = async (
|
|||||||
languageCode,
|
languageCode,
|
||||||
path,
|
path,
|
||||||
rootUrl,
|
rootUrl,
|
||||||
description: descriptions[languageCode],
|
description: i18nService.getTranslation({
|
||||||
|
languageCode,
|
||||||
|
id: 'metaDescription'
|
||||||
|
}),
|
||||||
featureGraphicPath:
|
featureGraphicPath:
|
||||||
locales[path]?.featureGraphicPath ?? 'assets/cover.png',
|
locales[path]?.featureGraphicPath ?? 'assets/cover.png',
|
||||||
title: locales[path]?.title ?? title
|
title: locales[path]?.title ?? title
|
||||||
|
67
apps/api/src/services/i18n/i18n.service.ts
Normal file
67
apps/api/src/services/i18n/i18n.service.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { readFileSync, readdirSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
|
||||||
|
import { Logger } from '@nestjs/common';
|
||||||
|
import * as cheerio from 'cheerio';
|
||||||
|
|
||||||
|
export class I18nService {
|
||||||
|
private localesPath = join(__dirname, 'assets', 'locales');
|
||||||
|
private translations: { [locale: string]: cheerio.CheerioAPI } = {};
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
this.loadFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTranslation({
|
||||||
|
id,
|
||||||
|
languageCode
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
languageCode: string;
|
||||||
|
}): string {
|
||||||
|
const $ = this.translations[languageCode];
|
||||||
|
|
||||||
|
if (!$) {
|
||||||
|
Logger.warn(`Translation not found for locale '${languageCode}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const translatedText = $(
|
||||||
|
`trans-unit[id="${id}"] > ${
|
||||||
|
languageCode === DEFAULT_LANGUAGE_CODE ? 'source' : 'target'
|
||||||
|
}`
|
||||||
|
).text();
|
||||||
|
|
||||||
|
if (!translatedText) {
|
||||||
|
Logger.warn(
|
||||||
|
`Translation not found for id '${id}' in locale '${languageCode}'`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return translatedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadFiles() {
|
||||||
|
try {
|
||||||
|
const files = readdirSync(this.localesPath, 'utf-8');
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const xmlData = readFileSync(join(this.localesPath, file), 'utf8');
|
||||||
|
this.translations[this.parseLanguageCode(file)] =
|
||||||
|
this.parseXml(xmlData);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error, 'I18nService');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseLanguageCode(aFileName: string) {
|
||||||
|
const match = aFileName.match(/\.([a-zA-Z]+)\.xlf$/);
|
||||||
|
|
||||||
|
return match ? match[1] : DEFAULT_LANGUAGE_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseXml(xmlData: string): cheerio.CheerioAPI {
|
||||||
|
return cheerio.load(xmlData, { xmlMode: true });
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user