Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/app/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
},
"apply": "Anwenden",
"taxes": "Steuern",
"annualBillingTemplate": "Jahresplan, monatlich abgerechnet mit {{price}}{{currency}}/Monat für 12 Monate"
"annualBillingTemplate": "Jahresplan, abgerechnet mit {{currency}}{{priceNow}} für den ersten Monat, dann Verlängerung zu {{currency}}{{price}}/Monat"
},
"confirmCryptoPayment": {
"title": "Zahlung bestätigen",
Expand Down Expand Up @@ -2008,7 +2008,7 @@
"free": "Erhalten Sie bis zu 10 GB kostenlos",
"manageBilling": "Abrechnung verwalten",
"freeForever": "Für immer kostenlos",
"billedAnnually": "jährlich abgerechnet",
"billedAnnually": "/Monat jährlich abgerechnet",
"billedMonthly": "monatlich abgerechnet",
"year": "Jahr",
"month": "Monat",
Expand Down Expand Up @@ -2053,7 +2053,8 @@
"Einladen, teilen & zusammenarbeiten",
"Verschlüsseltes VPN",
"Antivirus",
"Cleaner (Bereinigungstool)"
"Cleaner (Bereinigungstool)",
"Meet"
]
},
"5TB": {
Expand Down
9 changes: 5 additions & 4 deletions src/app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
"emailMustNotBeEmpty": "Email must not be empty",
"privacyGuarantee": "Privacy guarantee: We do not share your information and will contact you only as needed to provide our service."
},
"addressBillingTitle": "Address Billing",
"addressBillingTitle": "Billing Address",
"crypto": "Crypto",
"addressBilling": {
"optional": {
Expand Down Expand Up @@ -305,7 +305,7 @@
},
"apply": "Apply",
"taxes": "Taxes",
"annualBillingTemplate": "Annual plan, billed monthly at {{price}}{{currency}}/month for 12 months"
"annualBillingTemplate": "Annual plan, billed at {{currency}}{{priceNow}} for the first month, then renews at {{currency}}{{price}}/month"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the text for all languages.

},
"confirmCryptoPayment": {
"title": "Confirm the payment",
Expand Down Expand Up @@ -2092,7 +2092,7 @@
"free": "Get up to 10 GB for free",
"manageBilling": "Manage billing",
"freeForever": "Free forever",
"billedAnnually": "billed annually",
"billedAnnually": "/mo billed annually",
"billedMonthly": "billed monthly",
"year": "Year",
"month": "Month",
Expand Down Expand Up @@ -2137,7 +2137,8 @@
"Invite, share & collaborate",
"Encrypted VPN",
"Antivirus",
"Cleaner"
"Cleaner",
"Meet"
]
},
"5TB": {
Expand Down
7 changes: 4 additions & 3 deletions src/app/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@
},
"apply": "Aplicar",
"taxes": "Impuestos",
"annualBillingTemplate": "Plan anual, facturado mensualmente a {{price}}{{currency}}/mes durante 12 meses"
"annualBillingTemplate": "Plan anual, facturado a {{currency}}{{priceNow}} el primer mes, luego se renueva a {{currency}}{{price}}/mes"
},
"confirmCryptoPayment": {
"title": "Confirmar el pago",
Expand Down Expand Up @@ -2071,7 +2071,7 @@
"year": "Año",
"month": "Mes",
"lifetime": "Lifetime",
"billedAnnually": "facturado anualmente",
"billedAnnually": "/mes facturado anualmente",
"billedMonthly": "facturado mensualmente",
"types": {
"essential": "Essential",
Expand Down Expand Up @@ -2113,7 +2113,8 @@
"Invitar, compartir y colaborar",
"VPN Cifrada",
"Antivirus",
"Cleaner"
"Cleaner",
"Meet"
]
},
"5TB": {
Expand Down
7 changes: 4 additions & 3 deletions src/app/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
},
"apply": "Appliquer",
"taxes": "Taxes",
"annualBillingTemplate": "Plan annuel, facturé mensuellement à {{price}}{{currency}}/mois pendant 12 mois"
"annualBillingTemplate": "Plan annuel, facturé {{currency}}{{priceNow}} pour le premier mois, puis renouvelé à {{currency}}{{price}}/mois"
},
"confirmCryptoPayment": {
"title": "Confirmer le paiement",
Expand Down Expand Up @@ -2014,7 +2014,7 @@
"free": "Obtenez jusqu'à 10 Go gratuitement",
"manageBilling": "Gérer la facturation",
"freeForever": "Gratuit à vie",
"billedAnnually": "facturé annuellement",
"billedAnnually": "/mois facturé annuellement",
"billedMonthly": "facturé mensuellement",
"year": "Année",
"month": "Mois",
Expand Down Expand Up @@ -2059,7 +2059,8 @@
"Inviter, partager et collaborer",
"VPN Chiffré",
"Antivirus",
"Nettoyeur"
"Nettoyeur",
"Meet"
]
},
"5TB": {
Expand Down
7 changes: 4 additions & 3 deletions src/app/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@
},
"apply": "Applica",
"taxes": "Tasse",
"annualBillingTemplate": "Piano annuale, fatturato mensilmente a {{price}}{{currency}}/mese per 12 mesi"
"annualBillingTemplate": "Piano annuale, fatturato {{currency}}{{priceNow}} per il primo mese, poi si rinnova a {{currency}}{{price}}/mese"
},
"confirmCryptoPayment": {
"title": "Conferma il pagamento",
Expand Down Expand Up @@ -2121,7 +2121,7 @@
"free": "Ottieni fino a 10 GB gratis",
"manageBilling": "Gestisci la fatturazione",
"freeForever": "Gratis per sempre",
"billedAnnually": "fatturato annualmente",
"billedAnnually": "/mese fatturato annualmente",
"billedMonthly": "fatturato mensilmente",
"year": "Anno",
"month": "Mese",
Expand Down Expand Up @@ -2166,7 +2166,8 @@
"Invita, condividi e collabora",
"VPN Crittografata",
"Antivirus",
"Cleaner (Pulitore)"
"Cleaner (Pulitore)",
"Meet"
]
},
"5TB": {
Expand Down
7 changes: 4 additions & 3 deletions src/app/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
},
"apply": "Применить",
"taxes": "Налоги",
"annualBillingTemplate": "Годовой план, ежемесячная оплата {{price}}{{currency}}/мес. в течение 12 месяцев"
"annualBillingTemplate": "Годовой план, списание {{currency}}{{priceNow}} за первый месяц, затем продление по {{currency}}{{price}}/мес."
},
"confirmCryptoPayment": {
"title": "Подтвердить платеж",
Expand Down Expand Up @@ -2029,7 +2029,7 @@
"free": "Получите до 10 ГБ бесплатно",
"manageBilling": "Управление платежами",
"freeForever": "Бесплатно навсегда",
"billedAnnually": "оплачиваемый ежегодно",
"billedAnnually": "/мес. при годовой оплате",
"billedMonthly": "оплачиваемый ежемесячно",
"year": "Год",
"month": "Месяц",
Expand Down Expand Up @@ -2074,7 +2074,8 @@
"Приглашение, обмен и совместная работа",
"Зашифрованный VPN",
"Антивирус",
"Cleaner (Очиститель)"
"Cleaner (Очиститель)",
"Meet"
]
},
"5TB": {
Expand Down
7 changes: 4 additions & 3 deletions src/app/i18n/locales/tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@
},
"apply": "應用",
"taxes": "稅金",
"annualBillingTemplate": "年度計劃,每月 {{price}}{{currency}}/月,持續 12 個月"
"annualBillingTemplate": "年度計劃,首月收費 {{currency}}{{priceNow}},之後每月 {{currency}}{{price}}/月 自動續訂"
},
"confirmCryptoPayment": {
"title": "確認付款",
Expand Down Expand Up @@ -2018,7 +2018,7 @@
"free": "免費獲取最多 10GB",
"manageBilling": "管理帳單",
"freeForever": "永久免費",
"billedAnnually": "按年計費",
"billedAnnually": "/月 按年計費",
"billedMonthly": "按月計費",
"year": "年",
"month": "月",
Expand Down Expand Up @@ -2063,7 +2063,8 @@
"邀請、共享和協作",
"加密 VPN",
"防毒軟體",
"清理工具 (Cleaner)"
"清理工具 (Cleaner)",
"Meet"
],
"comingSoonFeatures": []
},
Expand Down
7 changes: 4 additions & 3 deletions src/app/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
},
"apply": "应用",
"taxes": "税费",
"annualBillingTemplate": "年度计划,每月 {{price}}{{currency}}/月,持续 12 个月"
"annualBillingTemplate": "年度计划,首月收费 {{currency}}{{priceNow}},之后每月 {{currency}}{{price}}/月 自动续订"
},
"confirmCryptoPayment": {
"title": "确认付款",
Expand Down Expand Up @@ -2056,7 +2056,7 @@
"free": "免费获取最多 10GB",
"manageBilling": "管理账单",
"freeForever": "永久免费",
"billedAnnually": "按年计费",
"billedAnnually": "/月 按年计费",
"billedMonthly": "按月计费",
"year": "年",
"month": "月",
Expand Down Expand Up @@ -2101,7 +2101,8 @@
"邀请、共享和协作",
"加密 VPN",
"杀毒软件",
"清理工具 (Cleaner)"
"清理工具 (Cleaner)",
"Meet"
]
},
"5TB": {
Expand Down
2 changes: 1 addition & 1 deletion src/views/Checkout/components/CheckoutProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export const CheckoutProductCard = ({
</div>
</div>
{priceData.interval === 'month' && (
<p className="text-gray-60">
<p className="text-gray-60 text-sm">
{translate('checkout.productCard.annualBillingTemplate', {
priceNow: totalAmountFormatted,
price: normalPriceAmount,
Expand Down
22 changes: 12 additions & 10 deletions src/views/Checkout/utils/formatPrice.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, test, expect } from 'vitest';
import { formatPrice } from './formatPrice';

describe('Formatting the price to have 2 decimals', () => {
Expand All @@ -7,11 +7,11 @@ describe('Formatting the price to have 2 decimals', () => {
});

describe('The value has less or exactly 2 decimals', () => {
it('When the user has a price with 1 decimal, the function returns 2 decimals (100.5 -> 100.50)', () => {
test('When the user has a price with 1 decimal, the function returns 2 decimals (100.5 -> 100.50)', () => {
expect(formatPrice(100.5)).toBe('100.50');
});

it('When the user has a price with 2 decimals, the function returns 2 decimals (99.99 -> 99.99)', () => {
test('When the user has a price with 2 decimals, the function returns 2 decimals (99.99 -> 99.99)', () => {
expect(formatPrice(99.99)).toBe('99.99');
});
});
Expand All @@ -20,15 +20,17 @@ describe('Formatting the price to have 2 decimals', () => {
expect(formatPrice(20.0)).toBe('20');
});

describe('The price has more than 2 decimals', () => {
it('When the price has more than 2 decimals, then the function returns the price with 2 decimals (truncated with high precision, 10.456 -> 10.45 - 10.001 -> 10 - 1.999 -> 1.99)', () => {
expect(formatPrice(10.456)).toBe('10.45');
expect(formatPrice(10.001)).toBe('10');
expect(formatPrice(1.999)).toBe('1.99');
});
test('When the price has more than 2 decimals, then the function returns the price rounded to 2 decimals (10.456 -> 10.46 - 10.001 -> 10 - 1.999 -> 2)', () => {
expect(formatPrice(10.456)).toBe('10.46');
expect(formatPrice(10.001)).toBe('10');
expect(formatPrice(1.999)).toBe('2');
});

it('Handles edge case where value is nearly integer due to float error', () => {
test('When the value is nearly integer due to float error, then it returns without decimals', () => {
expect(formatPrice(10.0000001)).toBe('10');
});

test('When there is a floating point precision error (19.99 * 100 = 1998.999... in JS), then it returns 2 decimals', () => {
expect(formatPrice(19.99)).toBe('19.99');
});
});
2 changes: 1 addition & 1 deletion src/views/Checkout/utils/formatPrice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const formatPrice = (price: number) => {
const truncated = Math.floor(Number(price.toFixed(8)) * 100) / 100;
const truncated = Math.round(Number(price.toFixed(8)) * 100) / 100;
const formatted = truncated.toFixed(2);
return formatted.endsWith('.00') ? String(truncated) : formatted;
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const PlanCard = ({
isLoading,
disableActionButton,
}: PlanCardProps) => {
const userText = ' ' + t('preferences.account.plans.billedAnnually');
const userText = t('preferences.account.plans.billedAnnually');

return (
<div className={'flex w-80 flex-col rounded-xl border border-gray-10 bg-gray-5 p-4 '}>
Expand Down
Loading