mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 06:03:45 +01:00
[web] Use localized number formatting for currencies (#17622)
* Add a unit test on `SubscriptionFormatters.formatPrice` * Add JSDoc to `formatPrice` Also: Name the functions before exporting: This fixes my IDE (WebStorm) navigation * Make `'USD'` the default param instead of reassigning * Create `formatCurrency` function * Use `formatCurrency` in SubscriptionFormatters * Use an `isNoCentsCurrency` logic for `CLP` `JPY` `KRW` `VND` And remove custom `CLP` logic and locale * Add `locale` param to `formatPrice` * Generate `groups.json` and `localizedPlanPricing.json` ``` bin/exec web node ./scripts/recurly/recurly_prices.js --download -o prices.json bin/exec web node ./scripts/plan-prices/plans.js -f ../../prices.json -o dir ``` * Update scripts/plan-prices/plans.js to generate numbers instead of localized amounts * Generate `groups.json` and `localizedPlanPricing.json` ``` bin/exec web node ./scripts/recurly/recurly_prices.js --download -o prices.json bin/exec web node ./scripts/plan-prices/plans.js -f ../../prices.json -o dir ``` * Remove generation of `plans.json` As /services/web/frontend/js/main/plans.js was removed in https://github.com/overleaf/internal/pull/12593 * Sort currencies in alphabetical order in scripts/plan-prices/plans.js * Generate `groups.json` and `localizedPlanPricing.json` ``` bin/exec web node ./scripts/recurly/recurly_prices.js --download -o prices.json bin/exec web node ./scripts/plan-prices/plans.js -f ../../prices.json -o dir ``` * Use `formatCurrency` in price-summary.tsx * Use `formatCurrency` in Subscription Pug files * Fix unit tests SubscriptionHelperTests.js * Remove unused `currencySymbol` * Change to `formatCurrency` in other React components * Add `CurrencyCode` JSDoc types * Duplicate `formatCurrency` into services/web/app/src/util * Wrap tests in a top-level describe block * Use `narrowSymbol` * Fix tests with `narrowSymbol` expects * Revert deletion of old `formatPrice` in SubscriptionFormatters.js * Rename `formatCurrency` -> `formatCurrencyLocalized` * Revert deletion of `CurrencySymbol` * Add split-test in SubscriptionController.js * Add split-test in SubscriptionViewModelBuilder.js * Add split-test in plans * Add split-test in subscription-dashboard-context.tsx * Add split-test in 4 more components * Update tests * Show currency and payment methods in interstitial page * Fix `–` being printed. Use `–` instead * Fix test with NOK * Storybook: Fix missing `SplitTestProvider` * Storybook: Revert "Remove unused `currencySymbol`" This reverts commit e55387d4753f97bbf8e39e0fdc3ad17312122aaa. * Replace `getSplitTestVariant` by `useSplitTestContext` * Use parameterize currencyFormat in `generateInitialLocalizedGroupPrice` * Fixup import paths of `formatCurrencyLocalized` * Replace `% 1 === 0` by `Number.isInteger` * Add comment explaining that any combinations of languages/currencies could happen * Fixup after rebase: import `useSplitTestContext` * Revert "Remove SplitTestProvider from subscription root" This reverts commit be9f378fda715b86589ab0759737581c72321d87. * Revert "Remove split test provider from some tests" This reverts commit 985522932b550cfd38fa6a4f4c3d2ebaee6ff7df. GitOrigin-RevId: 59a83cbbe0f7cc7e45f189c654e23fcf9bfa37af
This commit is contained in:
@@ -9,7 +9,6 @@ The scripts will put the output results into the `output` folder.
|
||||
_Command_ `node plans.js -f fileName -o outputdir` - generates three json files:
|
||||
|
||||
- `localizedPlanPricing.json` for `/services/web/config/settings.overrides.saas.js`
|
||||
- `plans.json` for `/services/web/frontend/js/main/plans.js`
|
||||
- `groups.json` for `/services/web/app/templates/plans/groups.json`
|
||||
|
||||
The input file can be in `.csv` or `.json` format
|
||||
|
||||
@@ -39,118 +39,38 @@ const plansMap = {
|
||||
professional: 'professional',
|
||||
}
|
||||
|
||||
const currencies = {
|
||||
USD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
EUR: {
|
||||
symbol: '€',
|
||||
placement: 'before',
|
||||
},
|
||||
GBP: {
|
||||
symbol: '£',
|
||||
placement: 'before',
|
||||
},
|
||||
SEK: {
|
||||
symbol: ' kr',
|
||||
placement: 'after',
|
||||
},
|
||||
CAD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
NOK: {
|
||||
symbol: ' kr',
|
||||
placement: 'after',
|
||||
},
|
||||
DKK: {
|
||||
symbol: ' kr',
|
||||
placement: 'after',
|
||||
},
|
||||
AUD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
NZD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
CHF: {
|
||||
symbol: 'Fr ',
|
||||
placement: 'before',
|
||||
},
|
||||
SGD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
INR: {
|
||||
symbol: '₹',
|
||||
placement: 'before',
|
||||
},
|
||||
BRL: {
|
||||
code: 'BRL',
|
||||
locale: 'pt-BR',
|
||||
symbol: 'R$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
MXN: {
|
||||
code: 'MXN',
|
||||
locale: 'es-MX',
|
||||
symbol: '$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
COP: {
|
||||
code: 'COP',
|
||||
locale: 'es-CO',
|
||||
symbol: '$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
CLP: {
|
||||
code: 'CLP',
|
||||
locale: 'es-CL',
|
||||
symbol: '$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
PEN: {
|
||||
code: 'PEN',
|
||||
locale: 'es-PE',
|
||||
symbol: 'S/ ',
|
||||
placement: 'before',
|
||||
},
|
||||
}
|
||||
|
||||
const buildCurrencyValue = (amount, currency) => {
|
||||
// Test using toLocaleString to format currencies for new LATAM regions
|
||||
if (currency.locale && currency.code) {
|
||||
return amount.toLocaleString(currency.locale, {
|
||||
style: 'currency',
|
||||
currency: currency.code,
|
||||
minimumFractionDigits: 0,
|
||||
})
|
||||
}
|
||||
return currency.placement === 'before'
|
||||
? `${currency.symbol}${amount}`
|
||||
: `${amount}${currency.symbol}`
|
||||
}
|
||||
const currencies = [
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CLP',
|
||||
'COP',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'INR',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PEN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'USD',
|
||||
]
|
||||
|
||||
function generatePlans(workSheetJSON) {
|
||||
// localizedPlanPricing object for settings.overrides.saas.js
|
||||
const localizedPlanPricing = {}
|
||||
// plans object for main/plans.js
|
||||
const plans = {}
|
||||
|
||||
for (const [currency, currencyDetails] of Object.entries(currencies)) {
|
||||
for (const currency of currencies) {
|
||||
localizedPlanPricing[currency] = {
|
||||
symbol: currencyDetails.symbol.trim(),
|
||||
free: {
|
||||
monthly: buildCurrencyValue(0, currencyDetails),
|
||||
annual: buildCurrencyValue(0, currencyDetails),
|
||||
monthly: 0,
|
||||
annual: 0,
|
||||
},
|
||||
}
|
||||
plans[currency] = {
|
||||
symbol: currencyDetails.symbol.trim(),
|
||||
}
|
||||
|
||||
for (const [outputKey, actualKey] of Object.entries(plansMap)) {
|
||||
const monthlyPlan = workSheetJSON.find(
|
||||
@@ -174,24 +94,17 @@ function generatePlans(workSheetJSON) {
|
||||
`Missing currency "${currency}" for plan "${actualKeyAnnual}"`
|
||||
)
|
||||
|
||||
const monthly = buildCurrencyValue(monthlyPlan[currency], currencyDetails)
|
||||
const monthlyTimesTwelve = buildCurrencyValue(
|
||||
monthlyPlan[currency] * 12,
|
||||
currencyDetails
|
||||
)
|
||||
const annual = buildCurrencyValue(annualPlan[currency], currencyDetails)
|
||||
const monthly = Number(monthlyPlan[currency])
|
||||
const monthlyTimesTwelve = Number(monthlyPlan[currency] * 12)
|
||||
const annual = Number(annualPlan[currency])
|
||||
|
||||
localizedPlanPricing[currency] = {
|
||||
...localizedPlanPricing[currency],
|
||||
[outputKey]: { monthly, monthlyTimesTwelve, annual },
|
||||
}
|
||||
plans[currency] = {
|
||||
...plans[currency],
|
||||
[outputKey]: { monthly, annual },
|
||||
}
|
||||
}
|
||||
}
|
||||
return { localizedPlanPricing, plans }
|
||||
return { localizedPlanPricing }
|
||||
}
|
||||
|
||||
function generateGroupPlans(workSheetJSON) {
|
||||
@@ -199,25 +112,6 @@ function generateGroupPlans(workSheetJSON) {
|
||||
data.plan_code.startsWith('group')
|
||||
)
|
||||
|
||||
const currencies = [
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CLP',
|
||||
'COP',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'INR',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'USD',
|
||||
'PEN',
|
||||
]
|
||||
const sizes = ['2', '3', '4', '5', '10', '20', '50']
|
||||
|
||||
const result = {}
|
||||
@@ -275,7 +169,7 @@ function writeFile(outputFile, data) {
|
||||
fs.writeFileSync(outputFile, data)
|
||||
}
|
||||
|
||||
const { localizedPlanPricing, plans } = generatePlans(input)
|
||||
const { localizedPlanPricing } = generatePlans(input)
|
||||
const groupPlans = generateGroupPlans(input)
|
||||
|
||||
if (argv.output) {
|
||||
@@ -291,10 +185,8 @@ if (argv.output) {
|
||||
process.exit(1)
|
||||
}
|
||||
writeFile(`${dir}/localizedPlanPricing.json`, formatJS(localizedPlanPricing))
|
||||
writeFile(`${dir}/plans.json`, formatJS(plans))
|
||||
writeFile(`${dir}/groups.json`, formatJSON(groupPlans))
|
||||
} else {
|
||||
console.log('PLANS', plans)
|
||||
console.log('LOCALIZED', localizedPlanPricing)
|
||||
console.log('GROUP PLANS', JSON.stringify(groupPlans, null, 2))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user