Commit 717a73a6 authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch '346620-automagically-obtain-translations' into 'master'

Resolve "Move add-on related data to GraphQL"

See merge request gitlab-org/gitlab!78436
parents 948a862c 3b9b980c
...@@ -20,16 +20,7 @@ export default { ...@@ -20,16 +20,7 @@ export default {
GlAlert, GlAlert,
OrderSummary, OrderSummary,
}, },
props: { inject: ['tags', 'i18n'],
config: {
required: true,
type: Object,
},
tags: {
required: true,
type: Array,
},
},
data() { data() {
return { return {
hasError: false, hasError: false,
...@@ -50,14 +41,14 @@ export default { ...@@ -50,14 +41,14 @@ export default {
return Number.isFinite(this.quantity) && this.quantity > 0; return Number.isFinite(this.quantity) && this.quantity > 0;
}, },
formulaText() { formulaText() {
const formulaText = this.isQuantityValid ? this.config.formula : this.config.formulaWithAlert; const formulaText = this.isQuantityValid ? this.i18n.formula : this.i18n.formulaWithAlert;
return sprintf(formulaText, { return sprintf(formulaText, {
quantity: formatNumber(this.config.quantityPerPack), quantity: formatNumber(this.plan.quantityPerPack),
units: this.config.productUnit, units: this.plan.productUnit,
}); });
}, },
formulaTotal() { formulaTotal() {
const total = sprintf(this.config.formulaTotal, { const total = sprintf(this.i18n.formulaTotal, {
quantity: formatNumber(this.totalUnits), quantity: formatNumber(this.totalUnits),
}); });
return this.isQuantityValid ? total : ''; return this.isQuantityValid ? total : '';
...@@ -67,20 +58,20 @@ export default { ...@@ -67,20 +58,20 @@ export default {
return plan; return plan;
}, },
totalUnits() { totalUnits() {
return this.quantity * this.config.quantityPerPack; return this.quantity * this.plan.quantityPerPack;
}, },
summaryTitle() { summaryTitle() {
return sprintf(this.config.summaryTitle(this.quantity), { quantity: this.quantity }); return sprintf(this.i18n.summaryTitle(this.quantity), { quantity: this.quantity });
}, },
summaryTotal() { summaryTotal() {
return sprintf(this.config.summaryTotal, { return sprintf(this.i18n.summaryTotal, {
quantity: formatNumber(this.totalUnits), quantity: formatNumber(this.totalUnits),
}); });
}, },
}, },
methods: { methods: {
pricePerUnitLabel(price) { pricePerUnitLabel(price) {
return sprintf(this.config.pricePerUnit, { return sprintf(this.i18n.pricePerUnit, {
selectedPlanPrice: price, selectedPlanPrice: price,
}); });
}, },
...@@ -137,10 +128,10 @@ export default { ...@@ -137,10 +128,10 @@ export default {
<checkout :plan="plan"> <checkout :plan="plan">
<template #purchase-details> <template #purchase-details>
<addon-purchase-details <addon-purchase-details
:product-label="config.productLabel" :product-label="plan.label"
:quantity="quantity" :quantity="quantity"
:show-alert="true" :show-alert="true"
:alert-text="config.alertText" :alert-text="i18n.alertText"
> >
<template #formula> <template #formula>
{{ formulaText }} {{ formulaText }}
...@@ -162,8 +153,8 @@ export default { ...@@ -162,8 +153,8 @@ export default {
> >
<order-summary <order-summary
:plan="plan" :plan="plan"
:title="config.title" :title="i18n.title"
:purchase-has-expiration="config.hasExpiration" :purchase-has-expiration="plan.hasExpiration"
@alertError="alertError" @alertError="alertError"
> >
<template #price-per-unit="{ price }"> <template #price-per-unit="{ price }">
......
...@@ -6,10 +6,6 @@ export const planTags = { ...@@ -6,10 +6,6 @@ export const planTags = {
STORAGE_PLAN: 'STORAGE_PLAN', STORAGE_PLAN: 'STORAGE_PLAN',
}; };
/* eslint-enable @gitlab/require-i18n-strings */ /* eslint-enable @gitlab/require-i18n-strings */
export const planCode = {
CI_1000_MINUTES_PLAN: 'ci_minutes',
STORAGE_PLAN: 'storage',
};
export const CUSTOMERSDOT_CLIENT = 'customersDotClient'; export const CUSTOMERSDOT_CLIENT = 'customersDotClient';
export const GITLAB_CLIENT = 'gitlabClient'; export const GITLAB_CLIENT = 'gitlabClient';
...@@ -26,40 +22,25 @@ export const STATE_TYPE = 'State'; ...@@ -26,40 +22,25 @@ export const STATE_TYPE = 'State';
export const CI_MINUTES_PER_PACK = 1000; export const CI_MINUTES_PER_PACK = 1000;
export const STORAGE_PER_PACK = 10; export const STORAGE_PER_PACK = 10;
// CI Minutes addon data translations
export const I18N_CI_MINUTES_PRODUCT_LABEL = s__('Checkout|CI minute pack'); export const I18N_CI_MINUTES_PRODUCT_LABEL = s__('Checkout|CI minute pack');
export const I18N_CI_MINUTES_PRODUCT_UNIT = s__('Checkout|minutes'); export const I18N_CI_MINUTES_PRODUCT_UNIT = s__('Checkout|minutes');
export const I18N_CI_MINUTES_FORMULA_TOTAL = s__('Checkout|%{quantity} CI minutes');
export const i18nCIMinutesSummaryTitle = (quantity) =>
n__('Checkout|%d CI minute pack', 'Checkout|%d CI minute packs', quantity);
export const I18N_CI_MINUTES_SUMMARY_TOTAL = s__('Checkout|Total minutes: %{quantity}');
export const I18N_CI_MINUTES_ALERT_TEXT = s__(
"Checkout|CI minute packs are only used after you've used your subscription's monthly quota. The additional minutes will roll over month to month and are valid for one year.",
);
export const I18N_CI_MINUTES_PRICE_PER_UNIT = s__(
'Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes',
);
export const I18N_CI_MINUTES_TITLE = s__("Checkout|%{name}'s CI minutes");
// Storage addon translations
export const I18N_STORAGE_PRODUCT_LABEL = s__('Checkout|Storage packs'); export const I18N_STORAGE_PRODUCT_LABEL = s__('Checkout|Storage packs');
export const I18N_STORAGE_PRODUCT_UNIT = s__('Checkout|GB'); export const I18N_STORAGE_PRODUCT_UNIT = s__('Checkout|GB');
export const I18N_STORAGE_FORMULA_TOTAL = s__('Checkout|%{quantity} GB of storage');
export const i18nStorageSummaryTitle = (quantity) =>
n__('Checkout|%{quantity} storage pack', 'Checkout|%{quantity} storage packs', quantity);
export const I18N_STORAGE_SUMMARY_TOTAL = s__('Checkout|Total storage: %{quantity} GB');
export const I18N_STORAGE_PRICE_PER_UNIT = s__(
'Checkout|$%{selectedPlanPrice} per 10 GB storage pack per year',
);
export const I18N_STORAGE_TITLE = s__("Checkout|%{name}'s storage subscription");
export const I18N_STORAGE_TOOLTIP_NOTE = s__( export const I18N_STORAGE_TOOLTIP_NOTE = s__(
'Checkout|Your storage subscription has the same term as your main subscription, and the price is prorated accordingly.', 'Checkout|Your storage subscription has the same term as your main subscription, and the price is prorated accordingly.',
); );
// Shared addon translations
export const I18N_DETAILS_STEP_TITLE = s__('Checkout|Purchase details'); export const I18N_DETAILS_STEP_TITLE = s__('Checkout|Purchase details');
export const I18N_DETAILS_NEXT_STEP_BUTTON_TEXT = s__('Checkout|Continue to billing'); export const I18N_DETAILS_NEXT_STEP_BUTTON_TEXT = s__('Checkout|Continue to billing');
export const I18N_DETAILS_INVALID_QUANTITY_MESSAGE = s__('Checkout|Enter a number greater than 0'); export const I18N_DETAILS_INVALID_QUANTITY_MESSAGE = s__('Checkout|Enter a number greater than 0');
export const I18N_DETAILS_FORMULA = s__('Checkout|x %{quantity} %{units} per pack ='); export const I18N_DETAILS_FORMULA = s__('Checkout|x %{quantity} %{units} per pack =');
export const I18N_DETAILS_FORMULA_WITH_ALERT = s__('Checkout|x %{quantity} %{units} per pack'); export const I18N_DETAILS_FORMULA_WITH_ALERT = s__('Checkout|x %{quantity} %{units} per pack');
// Summary translations
export const I18N_SUMMARY_QUANTITY = s__('Checkout|(x%{quantity})'); export const I18N_SUMMARY_QUANTITY = s__('Checkout|(x%{quantity})');
export const I18N_SUMMARY_DATES = s__('Checkout|%{startDate} - %{endDate}'); export const I18N_SUMMARY_DATES = s__('Checkout|%{startDate} - %{endDate}');
export const I18N_SUMMARY_SUBTOTAL = s__('Checkout|Subtotal'); export const I18N_SUMMARY_SUBTOTAL = s__('Checkout|Subtotal');
...@@ -72,3 +53,30 @@ export const I18N_SUMMARY_TOTAL = s__('Checkout|Total'); ...@@ -72,3 +53,30 @@ export const I18N_SUMMARY_TOTAL = s__('Checkout|Total');
export const I18N_API_ERROR = s__( export const I18N_API_ERROR = s__(
'Checkout|An unknown error has occurred. Please try again by refreshing this page.', 'Checkout|An unknown error has occurred. Please try again by refreshing this page.',
); );
// Addon label translations
export const I18N_CI_1000_MINUTES_PLAN = {
alertText: s__(
"Checkout|CI minute packs are only used after you've used your subscription's monthly quota. The additional minutes will roll over month to month and are valid for one year.",
),
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: s__('Checkout|%{quantity} CI minutes'),
pricePerUnit: s__('Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes'),
summaryTitle: (quantity) =>
n__('Checkout|%d CI minute pack', 'Checkout|%d CI minute packs', quantity),
summaryTotal: s__('Checkout|Total minutes: %{quantity}'),
title: s__("Checkout|%{name}'s CI minutes"),
};
export const I18N_STORAGE_PLAN = {
alertText: '',
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: s__('Checkout|%{quantity} GB of storage'),
pricePerUnit: s__('Checkout|$%{selectedPlanPrice} per 10 GB storage pack per year'),
summaryTitle: (quantity) =>
n__('Checkout|%{quantity} storage pack', 'Checkout|%{quantity} storage packs', quantity),
summaryTotal: s__('Checkout|Total storage: %{quantity} GB'),
title: s__("Checkout|%{name}'s storage subscription"),
};
...@@ -11,12 +11,16 @@ import { ...@@ -11,12 +11,16 @@ import {
I18N_CI_MINUTES_PRODUCT_UNIT, I18N_CI_MINUTES_PRODUCT_UNIT,
I18N_STORAGE_PRODUCT_LABEL, I18N_STORAGE_PRODUCT_LABEL,
I18N_STORAGE_PRODUCT_UNIT, I18N_STORAGE_PRODUCT_UNIT,
planCode,
STORAGE_PER_PACK, STORAGE_PER_PACK,
} from 'ee/subscriptions/buy_addons_shared/constants'; } from 'ee/subscriptions/buy_addons_shared/constants';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql'; import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import createFlash from '~/flash'; import createFlash from '~/flash';
const planCode = {
CI_1000_MINUTES_PLAN: 'ci_minutes',
STORAGE_PLAN: 'storage',
};
const planData = { const planData = {
[planCode.CI_1000_MINUTES_PLAN]: { [planCode.CI_1000_MINUTES_PLAN]: {
hasExpiration: false, hasExpiration: false,
......
<script>
import BuyAddonsApp from 'ee/subscriptions/buy_addons_shared/components/app.vue';
import {
CI_MINUTES_PER_PACK,
planTags,
I18N_CI_MINUTES_PRICE_PER_UNIT,
I18N_CI_MINUTES_PRODUCT_LABEL,
I18N_CI_MINUTES_PRODUCT_UNIT,
I18N_DETAILS_FORMULA,
I18N_DETAILS_FORMULA_WITH_ALERT,
I18N_CI_MINUTES_FORMULA_TOTAL,
i18nCIMinutesSummaryTitle,
I18N_CI_MINUTES_SUMMARY_TOTAL,
I18N_CI_MINUTES_ALERT_TEXT,
I18N_CI_MINUTES_TITLE,
} from 'ee/subscriptions/buy_addons_shared/constants';
export default {
components: {
BuyAddonsApp,
},
computed: {
tags() {
return [planTags.CI_1000_MINUTES_PLAN];
},
config() {
// These will move into the GraphQL store. See: https://gitlab.com/gitlab-org/gitlab/-/issues/346620
return {
alertText: I18N_CI_MINUTES_ALERT_TEXT,
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: I18N_CI_MINUTES_FORMULA_TOTAL,
hasExpiration: false,
pricePerUnit: I18N_CI_MINUTES_PRICE_PER_UNIT,
productLabel: I18N_CI_MINUTES_PRODUCT_LABEL,
productUnit: I18N_CI_MINUTES_PRODUCT_UNIT,
quantityPerPack: CI_MINUTES_PER_PACK,
summaryTitle: i18nCIMinutesSummaryTitle,
summaryTotal: I18N_CI_MINUTES_SUMMARY_TOTAL,
title: I18N_CI_MINUTES_TITLE,
};
},
},
};
</script>
<template>
<buy-addons-app :config="config" :tags="tags" />
</template>
import Vue from 'vue'; import Vue from 'vue';
import ensureData from '~/ensure_data'; import ensureData from '~/ensure_data';
import apolloProvider from '../buy_addons_shared/graphql'; import { planTags, I18N_CI_1000_MINUTES_PLAN } from 'ee/subscriptions/buy_addons_shared/constants';
import App from 'ee/subscriptions/buy_addons_shared/components/app.vue';
import { writeInitialDataToApolloCache } from '../buy_addons_shared/utils'; import { writeInitialDataToApolloCache } from '../buy_addons_shared/utils';
import App from './components/app.vue'; import apolloProvider from '../buy_addons_shared/graphql';
export default (el) => { export default (el) => {
if (!el) { if (!el) {
...@@ -13,6 +14,10 @@ export default (el) => { ...@@ -13,6 +14,10 @@ export default (el) => {
parseData: writeInitialDataToApolloCache.bind(null, apolloProvider), parseData: writeInitialDataToApolloCache.bind(null, apolloProvider),
data: el.dataset, data: el.dataset,
shouldLog: true, shouldLog: true,
provide: {
tags: [planTags.CI_1000_MINUTES_PLAN],
i18n: I18N_CI_1000_MINUTES_PLAN,
},
}); });
return new Vue({ return new Vue({
......
<script>
import BuyAddonsApp from 'ee/subscriptions/buy_addons_shared/components/app.vue';
import {
I18N_STORAGE_PRODUCT_LABEL,
I18N_STORAGE_PRODUCT_UNIT,
I18N_DETAILS_FORMULA,
I18N_STORAGE_FORMULA_TOTAL,
I18N_DETAILS_FORMULA_WITH_ALERT,
i18nStorageSummaryTitle,
I18N_STORAGE_SUMMARY_TOTAL,
I18N_STORAGE_TITLE,
I18N_STORAGE_PRICE_PER_UNIT,
planTags,
STORAGE_PER_PACK,
} from 'ee/subscriptions/buy_addons_shared/constants';
export default {
name: 'BuyStorageApp',
components: {
BuyAddonsApp,
},
computed: {
tags() {
return [planTags.STORAGE_PLAN];
},
config() {
// These will move into the GraphQL store. See: https://gitlab.com/gitlab-org/gitlab/-/issues/346620
return {
alertText: '',
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: I18N_STORAGE_FORMULA_TOTAL,
hasExpiration: true,
pricePerUnit: I18N_STORAGE_PRICE_PER_UNIT,
productLabel: I18N_STORAGE_PRODUCT_LABEL,
productUnit: I18N_STORAGE_PRODUCT_UNIT,
quantityPerPack: STORAGE_PER_PACK,
summaryTitle: i18nStorageSummaryTitle,
summaryTotal: I18N_STORAGE_SUMMARY_TOTAL,
title: I18N_STORAGE_TITLE,
};
},
},
};
</script>
<template>
<buy-addons-app :config="config" :tags="tags" />
</template>
import Vue from 'vue'; import Vue from 'vue';
import ensureData from '~/ensure_data'; import ensureData from '~/ensure_data';
import { planTags, I18N_STORAGE_PLAN } from 'ee/subscriptions/buy_addons_shared/constants';
import App from 'ee/subscriptions/buy_addons_shared/components/app.vue';
import apolloProvider from '../buy_addons_shared/graphql'; import apolloProvider from '../buy_addons_shared/graphql';
import { writeInitialDataToApolloCache } from '../buy_addons_shared/utils'; import { writeInitialDataToApolloCache } from '../buy_addons_shared/utils';
import App from './components/app.vue';
export default (el) => { export default (el) => {
if (!el) { if (!el) {
...@@ -13,10 +14,15 @@ export default (el) => { ...@@ -13,10 +14,15 @@ export default (el) => {
parseData: writeInitialDataToApolloCache.bind(null, apolloProvider), parseData: writeInitialDataToApolloCache.bind(null, apolloProvider),
data: el.dataset, data: el.dataset,
shouldLog: true, shouldLog: true,
provide: {
tags: [planTags.STORAGE_PLAN],
i18n: I18N_STORAGE_PLAN,
},
}); });
return new Vue({ return new Vue({
el, el,
name: 'BuyStorage',
apolloProvider, apolloProvider,
render(createElement) { render(createElement) {
return createElement(extendedApp); return createElement(extendedApp);
......
import BuyAddonsApp from 'ee/subscriptions/buy_addons_shared/components/app.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import App from 'ee/subscriptions/buy_minutes/components/app.vue';
import {
CI_MINUTES_PER_PACK,
planTags,
I18N_CI_MINUTES_PRICE_PER_UNIT,
I18N_CI_MINUTES_PRODUCT_LABEL,
I18N_CI_MINUTES_PRODUCT_UNIT,
I18N_DETAILS_FORMULA,
I18N_DETAILS_FORMULA_WITH_ALERT,
I18N_CI_MINUTES_FORMULA_TOTAL,
i18nCIMinutesSummaryTitle,
I18N_CI_MINUTES_SUMMARY_TOTAL,
I18N_CI_MINUTES_ALERT_TEXT,
I18N_CI_MINUTES_TITLE,
} from 'ee/subscriptions/buy_addons_shared/constants';
describe('Buy Minutes App', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMountExtended(App);
};
const findBuyAddonsApp = () => wrapper.findComponent(BuyAddonsApp);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('passes the correct tags', () => {
expect(findBuyAddonsApp().props('tags')).toEqual([planTags.CI_1000_MINUTES_PLAN]);
});
it('passes the correct config', () => {
expect(findBuyAddonsApp().props('config')).toMatchObject({
alertText: I18N_CI_MINUTES_ALERT_TEXT,
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: I18N_CI_MINUTES_FORMULA_TOTAL,
hasExpiration: false,
pricePerUnit: I18N_CI_MINUTES_PRICE_PER_UNIT,
productLabel: I18N_CI_MINUTES_PRODUCT_LABEL,
productUnit: I18N_CI_MINUTES_PRODUCT_UNIT,
quantityPerPack: CI_MINUTES_PER_PACK,
summaryTitle: i18nCIMinutesSummaryTitle,
summaryTotal: I18N_CI_MINUTES_SUMMARY_TOTAL,
title: I18N_CI_MINUTES_TITLE,
});
});
});
import BuyAddonsApp from 'ee/subscriptions/buy_addons_shared/components/app.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import App from 'ee/subscriptions/buy_storage/components/app.vue';
import {
I18N_STORAGE_PRODUCT_LABEL,
I18N_STORAGE_PRODUCT_UNIT,
I18N_DETAILS_FORMULA,
I18N_STORAGE_FORMULA_TOTAL,
I18N_DETAILS_FORMULA_WITH_ALERT,
i18nStorageSummaryTitle,
I18N_STORAGE_SUMMARY_TOTAL,
I18N_STORAGE_TITLE,
I18N_STORAGE_PRICE_PER_UNIT,
planTags,
STORAGE_PER_PACK,
} from 'ee/subscriptions/buy_addons_shared/constants';
describe('Buy Storage App', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMountExtended(App);
};
const findBuyAddonsApp = () => wrapper.findComponent(BuyAddonsApp);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('passes the correct tags', () => {
expect(findBuyAddonsApp().props('tags')).toEqual([planTags.STORAGE_PLAN]);
});
it('passes the correct config', () => {
expect(findBuyAddonsApp().props('config')).toMatchObject({
alertText: '',
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: I18N_STORAGE_FORMULA_TOTAL,
hasExpiration: true,
pricePerUnit: I18N_STORAGE_PRICE_PER_UNIT,
productLabel: I18N_STORAGE_PRODUCT_LABEL,
productUnit: I18N_STORAGE_PRODUCT_UNIT,
quantityPerPack: STORAGE_PER_PACK,
summaryTitle: i18nStorageSummaryTitle,
summaryTotal: I18N_STORAGE_SUMMARY_TOTAL,
title: I18N_STORAGE_TITLE,
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment