Browse Source

Task/localize country names (#6995)

* Localize country names

* Update changelog
pull/6902/head
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
363684526f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 6
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  3. 7
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  4. 12
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  5. 7
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
  6. 11
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  7. 8
      apps/client/src/app/pages/public/public-page.component.ts
  8. 14
      libs/common/src/lib/helper.ts
  9. 29
      libs/ui/src/lib/i18n.ts
  10. 6
      libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts
  11. 16
      libs/ui/src/lib/world-map-chart/world-map-chart.component.ts

1
CHANGELOG.md

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Harmonized the sector names across the data providers - Harmonized the sector names across the data providers
- Localized the country names
- Localized the sector names - Localized the sector names
- Centralized the asset profile override logic for manual adjustments - Centralized the asset profile override logic for manual adjustments
- Improved the styling in the user detail dialog of the admin control panel’s users section - Improved the styling in the user detail dialog of the admin control panel’s users section

6
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -8,6 +8,7 @@ import { UpdateAssetProfileDto } from '@ghostfolio/common/dtos';
import { import {
canDeleteAssetProfile, canDeleteAssetProfile,
DATE_FORMAT, DATE_FORMAT,
getCountryName,
getCurrencyFromSymbol, getCurrencyFromSymbol,
isCurrency isCurrency
} from '@ghostfolio/common/helper'; } from '@ghostfolio/common/helper';
@ -224,6 +225,7 @@ export class GfAssetProfileDialogComponent implements OnInit {
value: 'max' value: 'max'
} }
]; ];
protected readonly getCountryName = getCountryName;
protected historicalDataItems: LineChartItem[]; protected historicalDataItems: LineChartItem[];
protected isBenchmark = false; protected isBenchmark = false;
protected isDataGatheringEnabled: boolean; protected isDataGatheringEnabled: boolean;
@ -369,9 +371,9 @@ export class GfAssetProfileDialogComponent implements OnInit {
this.assetProfile?.countries && this.assetProfile?.countries &&
this.assetProfile.countries.length > 0 this.assetProfile.countries.length > 0
) { ) {
for (const { code, name, weight } of this.assetProfile.countries) { for (const { code, weight } of this.assetProfile.countries) {
this.countries[code] = { this.countries[code] = {
name, name: getCountryName({ code, locale: this.data.locale }),
value: weight value: weight
}; };
} }

7
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -269,7 +269,12 @@
i18n i18n
size="medium" size="medium"
[locale]="data.locale" [locale]="data.locale"
[value]="assetProfile?.countries[0].name" [value]="
getCountryName({
code: assetProfile?.countries[0].code,
locale: data.locale
})
"
>Country</gf-value >Country</gf-value
> >
</div> </div>

12
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -6,7 +6,11 @@ import {
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { CreateOrderDto } from '@ghostfolio/common/dtos'; import { CreateOrderDto } from '@ghostfolio/common/dtos';
import { DATE_FORMAT, downloadAsFile } from '@ghostfolio/common/helper'; import {
DATE_FORMAT,
downloadAsFile,
getCountryName
} from '@ghostfolio/common/helper';
import { import {
Activity, Activity,
DataProviderInfo, DataProviderInfo,
@ -121,6 +125,7 @@ export class GfHoldingDetailDialogComponent implements OnInit {
public dividendInBaseCurrencyPrecision = 2; public dividendInBaseCurrencyPrecision = 2;
public dividendYieldPercentWithCurrencyEffect: number; public dividendYieldPercentWithCurrencyEffect: number;
public feeInBaseCurrency: number; public feeInBaseCurrency: number;
public getCountryName = getCountryName;
public hasPermissionToCreateOwnTag: boolean; public hasPermissionToCreateOwnTag: boolean;
public hasPermissionToReadMarketDataOfOwnAssetProfile: boolean; public hasPermissionToReadMarketDataOfOwnAssetProfile: boolean;
public historicalDataItems: LineChartItem[]; public historicalDataItems: LineChartItem[];
@ -434,7 +439,10 @@ export class GfHoldingDetailDialogComponent implements OnInit {
if (SymbolProfile?.countries?.length > 0) { if (SymbolProfile?.countries?.length > 0) {
for (const country of SymbolProfile.countries) { for (const country of SymbolProfile.countries) {
this.countries[country.code] = { this.countries[country.code] = {
name: country.name, name: getCountryName({
code: country.code,
locale: this.data.locale
}),
value: country.weight value: country.weight
}; };
} }

7
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html

@ -272,7 +272,12 @@
i18n i18n
size="medium" size="medium"
[locale]="data.locale" [locale]="data.locale"
[value]="SymbolProfile.countries[0].name" [value]="
getCountryName({
code: SymbolProfile.countries[0].code,
locale: data.locale
})
"
>Country</gf-value >Country</gf-value
> >
</div> </div>

11
apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts

@ -3,7 +3,7 @@ import { AccountDetailDialogParams } from '@ghostfolio/client/components/account
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config'; import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config';
import { prettifySymbol } from '@ghostfolio/common/helper'; import { getCountryName, prettifySymbol } from '@ghostfolio/common/helper';
import { import {
AssetProfileIdentifier, AssetProfileIdentifier,
HoldingWithParents, HoldingWithParents,
@ -353,7 +353,7 @@ export class GfAllocationsPageComponent implements OnInit {
if (position.assetProfile.countries.length > 0) { if (position.assetProfile.countries.length > 0) {
for (const country of position.assetProfile.countries) { for (const country of position.assetProfile.countries) {
const { code, continent, name, weight } = country; const { code, continent, weight } = country;
if (this.continents[continent]?.value) { if (this.continents[continent]?.value) {
this.continents[continent].value += this.continents[continent].value +=
@ -363,7 +363,7 @@ export class GfAllocationsPageComponent implements OnInit {
: position.valueInPercentage); : position.valueInPercentage);
} else { } else {
this.continents[continent] = { this.continents[continent] = {
name: continent, name: translate(continent),
value: value:
weight * weight *
(isNumber(position.valueInBaseCurrency) (isNumber(position.valueInBaseCurrency)
@ -380,7 +380,10 @@ export class GfAllocationsPageComponent implements OnInit {
: position.valueInPercentage); : position.valueInPercentage);
} else { } else {
this.countries[code] = { this.countries[code] = {
name, name: getCountryName({
code,
locale: this.user?.settings?.locale
}),
value: value:
weight * weight *
(isNumber(position.valueInBaseCurrency) (isNumber(position.valueInBaseCurrency)

8
apps/client/src/app/pages/public/public-page.component.ts

@ -1,5 +1,5 @@
import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { prettifySymbol } from '@ghostfolio/common/helper'; import { getCountryName, prettifySymbol } from '@ghostfolio/common/helper';
import { import {
InfoItem, InfoItem,
PortfolioPosition, PortfolioPosition,
@ -186,14 +186,14 @@ export class GfPublicPageComponent implements OnInit {
if (position.assetProfile.countries.length > 0) { if (position.assetProfile.countries.length > 0) {
for (const country of position.assetProfile.countries) { for (const country of position.assetProfile.countries) {
const { code, continent, name, weight } = country; const { code, continent, weight } = country;
if (this.continents[continent]?.value) { if (this.continents[continent]?.value) {
this.continents[continent].value += this.continents[continent].value +=
weight * (position.valueInBaseCurrency ?? 0); weight * (position.valueInBaseCurrency ?? 0);
} else { } else {
this.continents[continent] = { this.continents[continent] = {
name: continent, name: translate(continent),
value: value:
weight * weight *
(this.publicPortfolioDetails.holdings[symbol] (this.publicPortfolioDetails.holdings[symbol]
@ -206,7 +206,7 @@ export class GfPublicPageComponent implements OnInit {
weight * (position.valueInBaseCurrency ?? 0); weight * (position.valueInBaseCurrency ?? 0);
} else { } else {
this.countries[code] = { this.countries[code] = {
name, name: getCountryName({ code }),
value: value:
weight * weight *
(this.publicPortfolioDetails.holdings[symbol] (this.publicPortfolioDetails.holdings[symbol]

14
libs/common/src/lib/helper.ts

@ -258,6 +258,20 @@ export function getCurrencyFromSymbol(aSymbol = '') {
return aSymbol.replace(DEFAULT_CURRENCY, ''); return aSymbol.replace(DEFAULT_CURRENCY, '');
} }
export function getCountryName({
code,
locale = getLocale()
}: {
code: string;
locale?: string;
}) {
try {
return new Intl.DisplayNames([locale], { type: 'region' }).of(code) ?? code;
} catch {
return code;
}
}
export function getDateFnsLocale(aLanguageCode?: string) { export function getDateFnsLocale(aLanguageCode?: string) {
if (aLanguageCode === 'ca') { if (aLanguageCode === 'ca') {
return ca; return ca;

29
libs/ui/src/lib/i18n.ts

@ -75,35 +75,6 @@ const locales = {
Oceania: $localize`Oceania`, Oceania: $localize`Oceania`,
'South America': $localize`South America`, 'South America': $localize`South America`,
// Countries
Armenia: $localize`Armenia`,
Argentina: $localize`Argentina`,
Australia: $localize`Australia`,
Austria: $localize`Austria`,
Belgium: $localize`Belgium`,
'British Virgin Islands': $localize`British Virgin Islands`,
Bulgaria: $localize`Bulgaria`,
Canada: $localize`Canada`,
'Czech Republic': $localize`Czech Republic`,
Finland: $localize`Finland`,
France: $localize`France`,
Germany: $localize`Germany`,
India: $localize`India`,
Indonesia: $localize`Indonesia`,
Italy: $localize`Italy`,
Japan: $localize`Japan`,
Netherlands: $localize`Netherlands`,
'New Zealand': $localize`New Zealand`,
Poland: $localize`Poland`,
Romania: $localize`Romania`,
Singapore: $localize`Singapore`,
'South Africa': $localize`South Africa`,
Switzerland: $localize`Switzerland`,
Thailand: $localize`Thailand`,
Ukraine: $localize`Ukraine`,
'United Kingdom': $localize`United Kingdom`,
'United States': $localize`United States`,
// Fear and Greed Index // Fear and Greed Index
EXTREME_FEAR: $localize`Extreme Fear`, EXTREME_FEAR: $localize`Extreme Fear`,
EXTREME_GREED: $localize`Extreme Greed`, EXTREME_GREED: $localize`Extreme Greed`,

6
libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

@ -37,8 +37,6 @@ import Color from 'color';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import OpenColor from 'open-color'; import OpenColor from 'open-color';
import { translate } from '../i18n';
const { const {
blue, blue,
cyan, cyan,
@ -390,7 +388,7 @@ export class GfPortfolioProportionChartComponent
return value > 0 return value > 0
? isUUID(symbol) ? isUUID(symbol)
? (translate(this.data[symbol]?.name) ?? symbol) ? (this.data[symbol]?.name ?? symbol)
: symbol : symbol
: ''; : '';
}, },
@ -453,7 +451,7 @@ export class GfPortfolioProportionChartComponent
symbol = $localize`No data available`; symbol = $localize`No data available`;
} }
const name = translate(this.data[symbol]?.name); const name = this.data[symbol]?.name;
let sum = 0; let sum = 0;

16
libs/ui/src/lib/world-map-chart/world-map-chart.component.ts

@ -1,4 +1,8 @@
import { getLocale, getNumberFormatGroup } from '@ghostfolio/common/helper'; import {
getCountryName,
getLocale,
getNumberFormatGroup
} from '@ghostfolio/common/helper';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -25,7 +29,7 @@ export class GfWorldMapChartComponent implements OnChanges, OnDestroy {
@Input() locale = getLocale(); @Input() locale = getLocale();
public isLoading = true; public isLoading = true;
public svgMapElement; public svgMapElement: any;
public constructor(private changeDetectorRef: ChangeDetectorRef) {} public constructor(private changeDetectorRef: ChangeDetectorRef) {}
@ -88,6 +92,14 @@ export class GfWorldMapChartComponent implements OnChanges, OnDestroy {
targetElementID: 'svgMap' targetElementID: 'svgMap'
}); });
this.svgMapElement.options.countryNames = Object.keys(
this.svgMapElement.countries
).reduce<{ [code: string]: string }>((names, code) => {
names[code] = getCountryName({ code, locale: this.locale });
return names;
}, {});
setTimeout(() => { setTimeout(() => {
this.isLoading = false; this.isLoading = false;

Loading…
Cancel
Save