0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

feat(console): apply quota limit for application creation ()

This commit is contained in:
Xiao Yijun 2023-07-20 11:29:55 +08:00 committed by GitHub
parent a7d8aec2e7
commit 769caeacb1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 275 additions and 144 deletions
packages
console/src
ds-components/RadioGroup
pages/Applications
components
ApplicationsPlaceholder
CreateForm
TypeDescription
index.tsx
phrases/src/locales
de/translation/admin-console
en/translation/admin-console
es/translation/admin-console
fr/translation/admin-console
it/translation/admin-console
ja/translation/admin-console
ko/translation/admin-console
pl-pl/translation/admin-console
pt-br/translation/admin-console
pt-pt/translation/admin-console
ru/translation/admin-console
tr-tr/translation/admin-console
zh-cn/translation/admin-console
zh-hk/translation/admin-console
zh-tw/translation/admin-console

View file

@ -32,6 +32,7 @@ export type Props = {
isDisabled?: boolean;
disabledLabel?: AdminConsoleKey;
icon?: ReactNode;
hasCheckIconForCard?: boolean;
};
function Radio({
@ -47,6 +48,7 @@ function Radio({
isDisabled,
disabledLabel,
icon,
hasCheckIconForCard = true,
}: Props) {
const handleKeyPress: KeyboardEventHandler<HTMLDivElement> = useCallback(
(event) => {
@ -79,7 +81,7 @@ function Radio({
>
<div className={styles.content}>
<input readOnly disabled type="radio" name={name} value={value} checked={isChecked} />
{type === 'card' && (
{type === 'card' && hasCheckIconForCard && (
<div className={styles.indicator}>
<Check />
</div>

View file

@ -1,55 +1,20 @@
import type { Application } from '@logto/schemas';
import { ApplicationType } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { isProduction } from '@/consts/env';
import Button from '@/ds-components/Button';
import useApi from '@/hooks/use-api';
import useConfigs from '@/hooks/use-configs';
import { applicationTypeI18nKey } from '@/types/applications';
import TypeDescription from '../TypeDescription';
import * as styles from './index.module.scss';
const defaultAppName = 'My App';
type Props = {
onCreate: (createdApp: Application) => void;
onSelect: (type: ApplicationType) => void;
};
function ApplicationsPlaceholder({ onCreate }: Props) {
function ApplicationsPlaceholder({ onSelect }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const [isCreating, setIsCreating] = useState(false);
const api = useApi();
const { updateConfigs } = useConfigs();
const handleCreate = async (type: ApplicationType) => {
if (isCreating) {
return;
}
setIsCreating(true);
const payload = {
type,
name: defaultAppName,
};
try {
const createdApp = await api.post('api/applications', { json: payload }).json<Application>();
void updateConfigs({
applicationCreated: true,
...conditional(
createdApp.type === ApplicationType.MachineToMachine && { m2mApplicationCreated: true }
),
});
onCreate(createdApp);
} finally {
setIsCreating(false);
}
};
return (
<div className={styles.placeholder}>
@ -64,13 +29,16 @@ function ApplicationsPlaceholder({ onCreate }: Props) {
title={t(`${applicationTypeI18nKey[type]}.title`)}
subtitle={t(`${applicationTypeI18nKey[type]}.subtitle`)}
description={t(`${applicationTypeI18nKey[type]}.description`)}
/**
* Todo: @xiaoyijun remove this condition on subscription features ready.
*/
hasProTag={!isProduction && type === ApplicationType.MachineToMachine}
/>
<Button
className={styles.createButton}
disabled={isCreating}
title="general.create"
title="general.select"
onClick={() => {
void handleCreate(type);
onSelect(type);
}}
/>
</div>

View file

@ -0,0 +1,105 @@
import { type Application, ApplicationType } from '@logto/schemas';
import { useMemo } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import useSWR from 'swr';
import ContactUsPhraseLink from '@/components/ContactUsPhraseLink';
import PlanName from '@/components/PlanName';
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
import { isProduction } from '@/consts/env';
import { ReservedPlanId } from '@/consts/subscriptions';
import Button from '@/ds-components/Button';
import useCurrentSubscriptionPlan from '@/hooks/use-current-subscription-plan';
import { isOverQuota } from '@/utils/quota';
type Props = {
selectedType?: ApplicationType;
isLoading: boolean;
onClickCreate: () => void;
};
function Footer({ selectedType, isLoading, onClickCreate }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell.paywall' });
const { data: currentPlan } = useCurrentSubscriptionPlan();
/**
* Todo: @xiaoyijun remove this condition on subscription features ready.
*/
const { data: allApplications } = useSWR<Application[]>(!isProduction && 'api/applications');
const m2mAppCount = useMemo(
() =>
allApplications?.filter(({ type }) => type === ApplicationType.MachineToMachine).length ?? 0,
[allApplications]
);
const nonM2mApplicationCount = allApplications ? allApplications.length - m2mAppCount : 0;
const isM2mAppsOverQuota = isOverQuota({
quotaKey: 'machineToMachineLimit',
plan: currentPlan,
usage: m2mAppCount,
});
const isNonM2mAppsOverQuota = isOverQuota({
quotaKey: 'applicationsLimit',
plan: currentPlan,
usage: nonM2mApplicationCount,
});
if (currentPlan && selectedType) {
const { id: planId, name: planName, quota } = currentPlan;
if (selectedType === ApplicationType.MachineToMachine && isM2mAppsOverQuota) {
return (
<QuotaGuardFooter>
{quota.machineToMachineLimit === 0 && planId === ReservedPlanId.free ? (
<Trans
components={{
a: <ContactUsPhraseLink />,
}}
>
{t('machine_to_machine_feature')}
</Trans>
) : (
<Trans
components={{
a: <ContactUsPhraseLink />,
planName: <PlanName name={planName} />,
}}
>
{t('machine_to_machine', { count: quota.machineToMachineLimit })}
</Trans>
)}
</QuotaGuardFooter>
);
}
if (selectedType !== ApplicationType.MachineToMachine && isNonM2mAppsOverQuota) {
return (
<QuotaGuardFooter>
<Trans
components={{
a: <ContactUsPhraseLink />,
planName: <PlanName name={planName} />,
}}
>
{t('applications', { count: quota.applicationsLimit })}
</Trans>
</QuotaGuardFooter>
);
}
}
return (
<Button
isLoading={isLoading}
htmlType="submit"
title="applications.create"
size="large"
type="primary"
onClick={onClickCreate}
/>
);
}
export default Footer;

View file

@ -1,11 +1,12 @@
import type { Application } from '@logto/schemas';
import { ApplicationType } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useEffect } from 'react';
import { useController, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import Modal from 'react-modal';
import Button from '@/ds-components/Button';
import { isProduction } from '@/consts/env';
import FormField from '@/ds-components/FormField';
import ModalLayout from '@/ds-components/ModalLayout';
import RadioGroup, { Radio } from '@/ds-components/RadioGroup';
@ -18,6 +19,7 @@ import { trySubmitSafe } from '@/utils/form';
import TypeDescription from '../TypeDescription';
import Footer from './Footer';
import * as styles from './index.module.scss';
type FormData = {
@ -28,20 +30,34 @@ type FormData = {
type Props = {
isOpen: boolean;
defaultCreateType?: ApplicationType;
onClose?: (createdApp?: Application) => void;
};
function CreateForm({ isOpen, onClose }: Props) {
function CreateForm({ isOpen, defaultCreateType, onClose }: Props) {
const { updateConfigs } = useConfigs();
const {
handleSubmit,
control,
register,
resetField,
formState: { errors, isSubmitting },
} = useForm<FormData>();
const {
field: { onChange, value, name, ref },
} = useController({ name: 'type', control, rules: { required: true } });
} = useController({
name: 'type',
control,
rules: { required: true },
});
useEffect(() => {
if (defaultCreateType) {
resetField('type', { defaultValue: defaultCreateType });
}
}, [defaultCreateType, resetField]);
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const api = useApi();
@ -80,16 +96,7 @@ function CreateForm({ isOpen, onClose }: Props) {
title="applications.create"
subtitle="applications.subtitle"
size="large"
footer={
<Button
isLoading={isSubmitting}
htmlType="submit"
title="applications.create"
size="large"
type="primary"
onClick={onSubmit}
/>
}
footer={<Footer selectedType={value} isLoading={isSubmitting} onClickCreate={onSubmit} />}
onClose={onClose}
>
<form>
@ -102,13 +109,24 @@ function CreateForm({ isOpen, onClose }: Props) {
type="card"
onChange={onChange}
>
{Object.values(ApplicationType).map((value) => (
<Radio key={value} value={value}>
{Object.values(ApplicationType).map((type) => (
<Radio
key={type}
value={type}
/**
* Todo: @xiaoyijun remove this condition on subscription features ready.
*/
hasCheckIconForCard={isProduction || type !== ApplicationType.MachineToMachine}
>
<TypeDescription
type={value}
title={t(`${applicationTypeI18nKey[value]}.title`)}
subtitle={t(`${applicationTypeI18nKey[value]}.subtitle`)}
description={t(`${applicationTypeI18nKey[value]}.description`)}
type={type}
title={t(`${applicationTypeI18nKey[type]}.title`)}
subtitle={t(`${applicationTypeI18nKey[type]}.subtitle`)}
description={t(`${applicationTypeI18nKey[type]}.description`)}
/**
* Todo: @xiaoyijun remove this condition on subscription features ready.
*/
hasProTag={!isProduction && type === ApplicationType.MachineToMachine}
/>
</Radio>
))}

View file

@ -1,6 +1,7 @@
@use '@/scss/underscore' as _;
.container {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
@ -34,4 +35,10 @@
font: var(--font-body-3);
}
}
.proTag {
position: absolute;
top: 0;
right: 0;
}
}

View file

@ -2,6 +2,7 @@ import type { ApplicationType } from '@logto/schemas';
import classNames from 'classnames';
import ApplicationIcon from '@/components/ApplicationIcon';
import ProTag from '@/components/ProTag';
import * as styles from './index.module.scss';
@ -11,15 +12,28 @@ type Props = {
description: string;
type: ApplicationType;
size?: 'large' | 'small';
hasProTag?: boolean;
};
function TypeDescription({ title, subtitle, description, type, size = 'large' }: Props) {
function TypeDescription({
title,
subtitle,
description,
type,
size = 'large',
hasProTag = false,
}: Props) {
return (
<div className={classNames(styles.container, styles[size])}>
<ApplicationIcon type={type} />
<div className={styles.title}>{title}</div>
<div className={styles.subtitle}>{subtitle}</div>
<div className={styles.description}>{description}</div>
{hasProTag && (
<div className={styles.proTag}>
<ProTag />
</div>
)}
</div>
);
}

View file

@ -1,6 +1,7 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { Application } from '@logto/schemas';
import { ApplicationType } from '@logto/schemas';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';
import useSWR from 'swr';
@ -37,7 +38,7 @@ function Applications() {
const { pathname, search } = useLocation();
const isShowingCreationForm = pathname === createApplicationPathname;
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const [defaultCreateType, setDefaultCreateType] = useState<ApplicationType>();
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({
page: 1,
});
@ -52,10 +53,6 @@ function Applications() {
const isLoading = !data && !error;
const [applications, totalCount] = data ?? [];
const mutateApplicationList = async (newApp: Application) => {
await mutate([[newApp, ...(applications ?? [])], (totalCount ?? 0) + 1]);
};
return (
<ListPage
title={{
@ -100,9 +97,12 @@ function Applications() {
],
placeholder: (
<ApplicationsPlaceholder
onCreate={async (newApp) => {
await mutateApplicationList(newApp);
navigate(buildNavigatePathPostAppCreation(newApp), { replace: true });
onSelect={async (createType) => {
setDefaultCreateType(createType);
navigate({
pathname: createApplicationPathname,
search,
});
}}
/>
),
@ -122,7 +122,9 @@ function Applications() {
widgets={
<CreateForm
isOpen={isShowingCreationForm}
defaultCreateType={defaultCreateType}
onClose={async (newApp) => {
setDefaultCreateType(undefined);
if (newApp) {
navigate(buildNavigatePathPostAppCreation(newApp), { replace: true });

View file

@ -55,6 +55,7 @@ const general = {
view: 'Anzeigen',
hide: 'Verbergen',
unknown_error: 'Unbekannter Fehler, bitte versuchen Sie es später erneut.',
select: 'Auswählen',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Sie haben das Limit von {{count, number}} <planName/>-Anwendungen erreicht. Um den Anforderungen Ihres Teams gerecht zu werden, upgraden Sie auf einen kostenpflichtigen Plan. Bei Fragen stehen wir Ihnen gerne zur Verfügung. <a>Kontaktieren Sie uns</a>.',
'{{count, number}} Anwendung von <planName/> erreicht. Plan upgraden, um den Bedürfnissen Ihres Teams gerecht zu werden. Für Unterstützung können Sie uns gerne <a>kontaktieren</a>.',
applications_other:
'Sie haben das Limit von {{count, number}} <planName/>-Anwendungen erreicht. Um den Anforderungen Ihres Teams gerecht zu werden, upgraden Sie auf einen kostenpflichtigen Plan. Bei Fragen stehen wir Ihnen gerne zur Verfügung. <a>Kontaktieren Sie uns</a>.',
'{{count, number}} Anwendungen von <planName/> erreicht. Plan upgraden, um den Bedürfnissen Ihres Teams gerecht zu werden. Für Unterstützung können Sie uns gerne <a>kontaktieren</a>.',
machine_to_machine_feature:
'Upgraden Sie auf einen kostenpflichtigen Plan, um eine Maschine-zu-Maschine-Anwendung zu erstellen und Zugriff auf alle Premium-Funktionen zu erhalten. Bei Fragen stehen wir Ihnen gerne zur Verfügung. <a>Kontaktieren Sie uns</a>.',
'Upgraden Sie auf einen kostenpflichtigen Tarif, um eine Maschinen-zu-Maschinen-Anwendung zu erstellen und Zugriff auf alle Premium-Funktionen zu erhalten. Für Unterstützung können Sie uns gerne <a>kontaktieren</a>.',
machine_to_machine:
'Sie haben das Limit von {{count, number}} <planName/>-Maschine-zu-Maschine-Anwendungen erreicht. Um den Anforderungen Ihres Teams gerecht zu werden, upgraden Sie auf einen kostenpflichtigen Plan. Bei Fragen stehen wir Ihnen gerne zur Verfügung. <a>Kontaktieren Sie uns</a>.',
'{{count, number}} Maschine-zu-Maschine-Anwendung von <planName/> erreicht. Plan upgraden, um den Bedürfnissen Ihres Teams gerecht zu werden. Für Unterstützung können Sie uns gerne <a>kontaktieren</a>.',
machine_to_machine_other:
'Sie haben das Limit von {{count, number}} <planName/>-Maschine-zu-Maschine-Anwendungen erreicht. Um den Anforderungen Ihres Teams gerecht zu werden, upgraden Sie auf einen kostenpflichtigen Plan. Bei Fragen stehen wir Ihnen gerne zur Verfügung. <a>Kontaktieren Sie uns</a>.',
'{{count, number}} Maschine-zu-Maschine-Anwendungen von <planName/> erreicht. Plan upgraden, um den Bedürfnissen Ihres Teams gerecht zu werden. Für Unterstützung können Sie uns gerne <a>kontaktieren</a>.',
resources:
'Sie haben das Limit von {{count, number}} <planName/>-API-Ressourcen erreicht. Upgraden Sie Ihren Plan, um den Anforderungen Ihres Teams gerecht zu werden. <a>Kontaktieren Sie uns</a> bei Bedarf.',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: 'View',
hide: 'Hide',
unknown_error: 'Unknown error, please try again later.',
select: 'Select', // UNTRANSLATED
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'{{count, number}} application of <planName/> limit reached. To meet your teams needs, upgrade to a paid plan. For any assistance, feel free to <a>contact us</a>.',
'{{count, number}} application of <planName/> limit reached. Upgrade plan to meet your teams needs. For any assistance, feel free to <a>contact us</a>.',
applications_other:
'{{count, number}} applications of <planName/> limit reached. To meet your teams needs, upgrade to a paid plan. For any assistance, feel free to <a>contact us</a>.',
'{{count, number}} applications of <planName/> limit reached. Upgrade plan to meet your teams needs. For any assistance, feel free to <a>contact us</a>.',
machine_to_machine_feature:
'Upgrade to a paid plan to create machine-to-machine application, along with access to all the premium features. For any assistance, feel free to <a>contact us</a>.',
machine_to_machine:
'{{count, number}} machine-to-machine application of <planName/> limit reached. To meet your teams needs, upgrade to a paid plan. For any assistance, feel free to <a>contact us</a>.',
'{{count, number}} machine-to-machine application of <planName/> limit reached. Upgrade plan to meet your teams needs. For any assistance, feel free to <a>contact us</a>.',
machine_to_machine_other:
'{{count, number}} machine-to-machine applications of <planName/> limit reached. To meet your teams needs, upgrade to a paid plan. For any assistance, feel free to <a>contact us</a>.',
'{{count, number}} machine-to-machine applications of <planName/> limit reached. Upgrade plan to meet your teams needs. For any assistance, feel free to <a>contact us</a>.',
resources:
'{{count, number}} API resource of <planName/> limit reached. Upgrade plan to meet your teams needs. <a>Contact us</a> for any assistant.',
resources_other:

View file

@ -55,6 +55,7 @@ const general = {
view: 'Ver',
hide: 'Ocultar',
unknown_error: 'Error desconocido, por favor inténtalo de nuevo más tarde.',
select: 'Seleccionar',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Has alcanzado el límite de {{count, number}} aplicaciones de <planName/>. Para satisfacer las necesidades de tu equipo, actualiza a un plan de pago. Si necesitas ayuda, no dudes en <a>contactarnos</a>.',
'Se ha alcanzado el límite de {{count, number}} aplicación de <planName/>. Actualiza el plan para satisfacer las necesidades de tu equipo. Para cualquier ayuda, no dudes en <a>contactarnos</a>.',
applications_other:
'Has alcanzado el límite de {{count, number}} aplicaciones de <planName/>. Para satisfacer las necesidades de tu equipo, actualiza a un plan de pago. Si necesitas ayuda, no dudes en <a>contactarnos</a>.',
'Se ha alcanzado el límite de {{count, number}} aplicaciones de <planName/>. Actualiza el plan para satisfacer las necesidades de tu equipo. Para cualquier ayuda, no dudes en <a>contactarnos</a>.',
machine_to_machine_feature:
'Actualiza a un plan de pago para crear una aplicación de máquina a máquina, junto con acceso a todas las funciones premium. Si necesitas ayuda, no dudes en <a>contactarnos</a>.',
'Actualiza a un plan de pago para crear aplicaciones de máquina a máquina, junto con acceso a todas las funciones premium. Para cualquier ayuda, no dudes en <a>contactarnos</a>.',
machine_to_machine:
'Has alcanzado el límite de {{count, number}} aplicaciones de máquina a máquina de <planName/>. Para satisfacer las necesidades de tu equipo, actualiza a un plan de pago. Si necesitas ayuda, no dudes en <a>contactarnos</a>.',
'Se ha alcanzado el límite de {{count, number}} aplicación de máquina a máquina de <planName/>. Actualiza el plan para satisfacer las necesidades de tu equipo. Para cualquier ayuda, no dudes en <a>contactarnos</a>.',
machine_to_machine_other:
'Has alcanzado el límite de {{count, number}} aplicaciones de máquina a máquina de <planName/>. Para satisfacer las necesidades de tu equipo, actualiza a un plan de pago. Si necesitas ayuda, no dudes en <a>contactarnos</a>.',
'Se ha alcanzado el límite de {{count, number}} aplicaciones de máquina a máquina de <planName/>. Actualiza el plan para satisfacer las necesidades de tu equipo. Para cualquier ayuda, no dudes en <a>contactarnos</a>.',
resources:
'Has alcanzado el límite de {{count, number}} recursos de API de <planName/>. Actualiza el plan para satisfacer las necesidades de tu equipo. <a>Contáctanos</a> si necesitas asistencia.',
resources_other:

View file

@ -55,6 +55,7 @@ const general = {
view: 'Vue',
hide: 'Cacher',
unknown_error: 'Erreur inconnue, veuillez réessayer ultérieurement.',
select: 'Sélectionner',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
"Vous avez atteint la limite de {{count, number}} application de <planName/>. Pour répondre aux besoins de votre équipe, passez à un plan payant. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
"Limite de {{count, number}} application de <planName/> atteinte. Mettez à niveau le plan pour répondre aux besoins de votre équipe. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
applications_other:
"Vous avez atteint la limite de {{count, number}} applications de <planName/>. Pour répondre aux besoins de votre équipe, passez à un plan payant. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
"Limite de {{count, number}} applications de <planName/> atteinte. Mettez à niveau le plan pour répondre aux besoins de votre équipe. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
machine_to_machine_feature:
"Mettez à niveau vers un plan payant pour créer des applications Machine-to-Machine, ainsi qu'un accès à toutes les fonctionnalités premium. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
"Passez à un abonnement payant pour créer des applications de machine à machine, ainsi que pour accéder à toutes les fonctionnalités premium. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
machine_to_machine:
"Vous avez atteint la limite de {{count, number}} application Machine-to-Machine de <planName/>. Pour répondre aux besoins de votre équipe, passez à un plan payant. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
"Limite de {{count, number}} application de machine à machine de <planName/> atteinte. Mettez à niveau le plan pour répondre aux besoins de votre équipe. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
machine_to_machine_other:
"Vous avez atteint la limite de {{count, number}} applications Machine-to-Machine de <planName/>. Pour répondre aux besoins de votre équipe, passez à un plan payant. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
"Limite de {{count, number}} applications de machine à machine de <planName/> atteinte. Mettez à niveau le plan pour répondre aux besoins de votre équipe. Pour toute assistance, n'hésitez pas à <a>nous contacter</a>.",
resources:
'Vous avez atteint la limite de {{count, number}} ressource API de <planName/>. Mettez à niveau votre plan pour répondre aux besoins de votre équipe. <a>Contactez-nous</a> pour toute assistance.',
resources_other:

View file

@ -55,6 +55,7 @@ const general = {
view: 'Vista',
hide: 'Nascondi',
unknown_error: 'Errore sconosciuto, riprova più tardi.',
select: 'Seleziona',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Hai raggiunto il limite di {{count, number}} applicazioni di <planName/>. Per soddisfare le esigenze del tuo team, passa a un piano a pagamento. Per qualsiasi assistenza, sentiti libero di <a>contattarci</a>.',
'Limite di {{count, number}} applicazione di <planName/> raggiunto. Aggiorna il piano per soddisfare le esigenze del tuo team. Per qualsiasi assistenza, non esitare a <a>contattarci</a>.',
applications_other:
'Hai raggiunto il limite di {{count, number}} applicazioni di <planName/>. Per soddisfare le esigenze del tuo team, passa a un piano a pagamento. Per qualsiasi assistenza, sentiti libero di <a>contattarci</a>.',
'Limite di {{count, number}} applicazioni di <planName/> raggiunto. Aggiorna il piano per soddisfare le esigenze del tuo team. Per qualsiasi assistenza, non esitare a <a>contattarci</a>.',
machine_to_machine_feature:
"Aggiorna a un piano a pagamento per creare un'applicazione macchina-macchina, insieme all'accesso a tutte le funzionalità premium. Per qualsiasi assistenza, sentiti libero di <a>contattarci</a>.",
'Aggiorna a un piano a pagamento per creare applicazioni machine-to-machine e accedere a tutte le funzionalità premium. Per qualsiasi assistenza, non esitare a <a>contattarci</a>.',
machine_to_machine:
'Hai raggiunto il limite di {{count, number}} applicazioni macchina-macchina di <planName/>. Per soddisfare le esigenze del tuo team, passa a un piano a pagamento. Per qualsiasi assistenza, sentiti libero di <a>contattarci</a>.',
'Limite di {{count, number}} applicazione machine-to-machine di <planName/> raggiunto. Aggiorna il piano per soddisfare le esigenze del tuo team. Per qualsiasi assistenza, non esitare a <a>contattarci</a>.',
machine_to_machine_other:
'Hai raggiunto il limite di {{count, number}} applicazioni macchina-macchina di <planName/>. Per soddisfare le esigenze del tuo team, passa a un piano a pagamento. Per qualsiasi assistenza, sentiti libero di <a>contattarci</a>.',
'Limite di {{count, number}} applicazioni machine-to-machine di <planName/> raggiunto. Aggiorna il piano per soddisfare le esigenze del tuo team. Per qualsiasi assistenza, non esitare a <a>contattarci</a>.',
resources:
'Hai raggiunto il limite di {{count, number}} risorse API di <planName/>. Aggiorna il piano per soddisfare le esigenze del tuo team. <a>Contattaci</a> per qualsiasi assistenza.',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: '表示',
hide: '非表示',
unknown_error: '不明なエラーが発生しました。後で再試行してください。',
select: '選択する',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'{{count, number}}の<planName/>アプリケーション制限に達しました。チームのニーズに合わせて有料プランにアップグレードしてください。<a>お問い合わせ</a>は何かお手伝いが必要な場合はお気軽にどうぞ。',
'{{count, number}}の<planName/>アプリケーション制限に達しました。チームのニーズに対応するため、プランをアップグレードしてください。サポートが必要な場合は、お気軽に<a>お問い合わせ</a>ください。',
applications_other:
'{{count, number}}の<planName/>アプリケーション制限に達しました。チームのニーズに合わせて有料プランにアップグレードしてください。<a>お問い合わせ</a>は何かお手伝いが必要な場合はお気軽にどうぞ。',
'{{count, number}}の<planName/>アプリケーション制限に達しました。チームのニーズに対応するため、プランをアップグレードしてください。サポートが必要な場合は、お気軽に<a>お問い合わせ</a>ください。',
machine_to_machine_feature:
'有料プランにアップグレードして、マシン・ツー・マシンのアプリケーションを作成し、すべてのプレミアム機能にアクセスしましょう。<a>お問い合わせ</a>は何かお手伝いが必要な場合はお気軽にどうぞ。',
'有料プランにアップグレードして、マシン間アプリケーションを作成し、すべてのプレミアム機能にアクセスしてください。サポートが必要な場合は、お気軽に<a>お問い合わせ</a>ください。',
machine_to_machine:
'{{count, number}}の<planName/>マシン・ツー・マシンのアプリケーション制限に達しました。チームのニーズに合わせて有料プランにアップグレードしてください。<a>お問い合わせ</a>は何かお手伝いが必要な場合はお気軽にどうぞ。',
'{{count, number}}個の<planName/>マシン間アプリケーション制限に達しました。チームのニーズに対応するため、プランをアップグレードしてください。サポートが必要な場合は、お気軽に<a>お問い合わせ</a>ください。',
machine_to_machine_other:
'{{count, number}}の<planName/>マシン・ツー・マシンのアプリケーション制限に達しました。チームのニーズに合わせて有料プランにアップグレードしてください。<a>お問い合わせ</a>は何かお手伝いが必要な場合はお気軽にどうぞ。',
'{{count, number}}個の<planName/>マシン間アプリケーション制限に達しました。チームのニーズに対応するため、プランをアップグレードしてください。サポートが必要な場合は、お気軽に<a>お問い合わせ</a>ください。',
resources:
'{{count, number}}の<planName/> APIリソース制限に達しました。チームのニーズに合わせてプランをアップグレードしてください。<a>お問い合わせ</a>は何かお手伝いが必要な場合はお気軽にどうぞ。',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: '보기',
hide: '숨기기',
unknown_error: '알 수 없는 오류가 발생했습니다. 나중에 다시 시도해주세요.',
select: '선택',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'<planName/>의 {{count, number}}개 애플리케이션 한도에 도달했습니다. 팀의 요구를 충족시키기 위해 유료 플랜으로 업그레이드하세요. 도움이 필요하면 <a>문의하기</a>로 연락 주세요.',
'<planName/>의 {{count, number}}개 애플리케이션 제한에 도달했습니다. 팀의 요구를 충족하기 위해 플랜을 업그레이드하십시오. 도움이 필요하면 <a>문의</a>해 주시기 바랍니다.',
applications_other:
'<planName/>의 {{count, number}}개 애플리케이션 한도에 도달했습니다. 팀의 요구를 충족시키기 위해 유료 플랜으로 업그레이드하세요. 도움이 필요하면 <a>문의하기</a>로 연락 주세요.',
'<planName/>의 {{count, number}}개 애플리케이션 제한에 도달했습니다. 팀의 요구를 충족하기 위해 플랜을 업그레이드하십시오. 도움이 필요하면 <a>문의</a>해 주시기 바랍니다.',
machine_to_machine_feature:
'유료 플랜으로 업그레이드하여 기계 간 애플리케이션을 생성하고 모든 프리미엄 기능에 액세스하세요. 도움이 필요하면 <a>문의하기</a>로 연락 주세요.',
'유료 플랜으로 업그레이드하여 기계 간 애플리케이션을 생성하고 모든 프리미엄 기능에 액세스하세요. 도움이 필요하면 <a>문의</a>해 주시기 바랍니다.',
machine_to_machine:
'<planName/>의 {{count, number}}개 기계 간 애플리케이션 한도에 도달했습니다. 팀의 요구를 충족시키기 위해 유료 플랜으로 업그레이드하세요. 도움이 필요하면 <a>문의하기</a>로 연락 주세요.',
'<planName/>의 {{count, number}}개 기계 간 애플리케이션 제한에 도달했습니다. 팀의 요구를 충족하기 위해 플랜을 업그레이드하십시오. 도움이 필요하면 <a>문의</a>해 주시기 바랍니다.',
machine_to_machine_other:
'<planName/>의 {{count, number}}개 기계 간 애플리케이션 한도에 도달했습니다. 팀의 요구를 충족시키기 위해 유료 플랜으로 업그레이드하세요. 도움이 필요하면 <a>문의하기</a>로 연락 주세요.',
'<planName/>의 {{count, number}}개 기계 간 애플리케이션 제한에 도달했습니다. 팀의 요구를 충족하기 위해 플랜을 업그레이드하십시오. 도움이 필요하면 <a>문의</a>해 주시기 바랍니다.',
resources:
'<planName/>의 {{count, number}}개 API 리소스 한도에 도달했습니다. 팀의 요구를 충족시키기 위해 플랜을 업그레이드하세요. 도움이 필요하면 <a>문의하기</a>로 연락 주세요.',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: 'Pokaż',
hide: 'Ukryj',
unknown_error: 'Nieznany błąd, spróbuj ponownie później.',
select: 'Wybierz',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Osiągnięto limit {{count, number}} aplikacji w planie <planName/>. Aby sprostać potrzebom twojego zespołu, ulepsz do płatnego planu. W razie potrzeby, skontaktuj się z nami <a>tutaj</a>.',
'Osiągnięto limit {{count, number}} aplikacji dla <planName/>. Zaktualizuj plan, aby sprostać potrzebom zespołu. W razie potrzeby pomocy, proszę <a>skontaktuj się z nami</a>.',
applications_other:
'Osiągnięto limit {{count, number}} aplikacji w planie <planName/>. Aby sprostać potrzebom twojego zespołu, ulepsz do płatnego planu. W razie potrzeby, skontaktuj się z nami <a>tutaj</a>.',
'Osiągnięto limit {{count, number}} aplikacji dla <planName/>. Zaktualizuj plan, aby sprostać potrzebom zespołu. W razie potrzeby pomocy, proszę <a>skontaktuj się z nami</a>.',
machine_to_machine_feature:
'Ulepsz do płatnego planu, aby tworzyć aplikacje między maszynami, razem z dostępem do wszystkich funkcji premium. W razie potrzeby, skontaktuj się z nami <a>tutaj</a>.',
'Zaktualizuj plan na płatny, aby tworzyć aplikacje maszynowe i uzyskać dostęp do wszystkich funkcji premium. W razie potrzeby pomocy, proszę <a>skontaktuj się z nami</a>.',
machine_to_machine:
'Osiągnięto limit {{count, number}} aplikacji między maszynami w planie <planName/>. Aby sprostać potrzebom twojego zespołu, ulepsz do płatnego planu. W razie potrzeby, skontaktuj się z nami <a>tutaj</a>.',
'Osiągnięto limit {{count, number}} aplikacji maszynowych dla <planName/>. Zaktualizuj plan, aby sprostać potrzebom zespołu. W razie potrzeby pomocy, proszę <a>skontaktuj się z nami</a>.',
machine_to_machine_other:
'Osiągnięto limit {{count, number}} aplikacji między maszynami w planie <planName/>. Aby sprostać potrzebom twojego zespołu, ulepsz do płatnego planu. W razie potrzeby, skontaktuj się z nami <a>tutaj</a>.',
'Osiągnięto limit {{count, number}} aplikacji maszynowych dla <planName/>. Zaktualizuj plan, aby sprostać potrzebom zespołu. W razie potrzeby pomocy, proszę <a>skontaktuj się z nami</a>.',
resources:
'Osiągnięto limit {{count, number}} zasobów API w planie <planName/>. Ulepsz plan, aby sprostać potrzebom twojego zespołu. Skontaktuj się z nami <a>tutaj</a>, jeśli potrzebujesz pomocy.',
resources_other:

View file

@ -55,6 +55,7 @@ const general = {
view: 'Visualizar',
hide: 'Ocultar',
unknown_error: 'Erro desconhecido, por favor tente novamente mais tarde.',
select: 'Selecionar',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Atingiu o limite de {{count, number}} aplicações de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicação do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
applications_other:
'Atingiu o limite de {{count, number}} aplicações de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicações do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
machine_to_machine_feature:
'Atualize para um plano pago para criar uma aplicação máquina-a-máquina, juntamente com acesso a todas as funcionalidades premium. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Faça upgrade para um plano pago para criar aplicativos de máquina para máquina, junto com acesso a todos os recursos premium. Para qualquer assistência, fique à vontade para <a>entrar em contato conosco</a>.',
machine_to_machine:
'Atingiu o limite de {{count, number}} aplicações máquina-a-máquina de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicação de máquina para máquina do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
machine_to_machine_other:
'Atingiu o limite de {{count, number}} aplicações máquina-a-máquina de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicações de máquina para máquina do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
resources:
'Atingiu o limite de {{count, number}} recursos de API de <planName/>. Atualize o plano para satisfazer as necessidades da sua equipa. <a>Contacte-nos</a> se precisar de assistência.',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: 'Ver',
hide: 'Esconder',
unknown_error: 'Erro desconhecido, por favor tente novamente mais tarde.',
select: 'Selecionar',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Atingiu o limite de {{count, number}} aplicações de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicação do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
applications_other:
'Atingiu o limite de {{count, number}} aplicações de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicações do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
machine_to_machine_feature:
'Atualize para um plano pago para criar uma aplicação máquina-a-máquina, juntamente com acesso a todas as funcionalidades premium. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Atualize para um plano pago para criar aplicação de máquina a máquina, juntamente com acesso a todos os recursos premium. Para qualquer assistência, fique à vontade para <a>entrar em contato conosco</a>.',
machine_to_machine:
'Atingiu o limite de {{count, number}} aplicações máquina-a-máquina de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicação de máquina a máquina do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
machine_to_machine_other:
'Atingiu o limite de {{count, number}} aplicações máquina-a-máquina de <planName/>. Para satisfazer as necessidades da sua equipa, atualize para um plano pago. Se precisar de ajuda, não hesite em <a>contactar-nos</a>.',
'Limite de {{count, number}} aplicações de máquina a máquina do <planName/> atingido. Atualize o plano para atender às necessidades da sua equipe. Para obter qualquer ajuda, sinta-se à vontade para <a>entrar em contato conosco</a>.',
resources:
'Atingiu o limite de {{count, number}} recursos de API de <planName/>. Atualize o plano para satisfazer as necessidades da sua equipa. <a>Contacte-nos</a> se precisar de assistência.',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: 'Просмотр',
hide: 'Скрыть',
unknown_error: 'Неизвестная ошибка, пожалуйста, попробуйте позже.',
select: 'Выбрать',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'Достигнут лимит {{count, number}} приложений в плане <planName/>. Для удовлетворения потребностей вашей команды повысьте до платного плана. Если вам нужна помощь, не стесняйтесь <a>связаться с нами</a>.',
'Достигнут лимит {{count, number}} приложения(й) для <planName/>. Обновите план, чтобы удовлетворить потребности вашей команды. При необходимости помощи, не стесняйтесь <a>связаться с нами</a>.',
applications_other:
'Достигнут лимит {{count, number}} приложений в плане <planName/>. Для удовлетворения потребностей вашей команды повысьте до платного плана. Если вам нужна помощь, не стесняйтесь <a>связаться с нами</a>.',
'Достигнут лимит {{count, number}} приложений для <planName/>. Обновите план, чтобы удовлетворить потребности вашей команды. При необходимости помощи, не стесняйтесь <a>связаться с нами</a>.',
machine_to_machine_feature:
овысьте до платного плана, чтобы создавать приложения машин-на-машине и получить доступ ко всем премиальным функциям. Если вам нужна помощь, не стесняйтесь <a>связаться с нами</a>.',
ерейдите на платный план, чтобы создать машинное приложение и получить доступ ко всем премиум-функциям. При необходимости помощи, не стесняйтесь <a>связаться с нами</a>.',
machine_to_machine:
'Достигнут лимит {{count, number}} приложений машин-на-машине в плане <planName/>. Для удовлетворения потребностей вашей команды повысьте до платного плана. Если вам нужна помощь, не стесняйтесь <a>связаться с нами</a>.',
'Достигнут лимит {{count, number}} машинных приложений для <planName/>. Обновите план, чтобы удовлетворить потребности вашей команды. При необходимости помощи, не стесняйтесь <a>связаться с нами</a>.',
machine_to_machine_other:
'Достигнут лимит {{count, number}} приложений машин-на-машине в плане <planName/>. Для удовлетворения потребностей вашей команды повысьте до платного плана. Если вам нужна помощь, не стесняйтесь <a>связаться с нами</a>.',
'Достигнут лимит {{count, number}} машинных приложений для <planName/>. Обновите план, чтобы удовлетворить потребности вашей команды. При необходимости помощи, не стесняйтесь <a>связаться с нами</a>.',
resources:
'Достигнут лимит {{count, number}} ресурсов API в плане <planName/>. Повысьте план, чтобы удовлетворить потребности вашей команды. <a>Свяжитесь с нами</a> для получения помощи.',
resources_other:

View file

@ -55,6 +55,7 @@ const general = {
view: 'Görünüm',
hide: 'Gizle',
unknown_error: 'Bilinmeyen hata, lütfen daha sonra tekrar deneyin.',
select: 'Seç',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'{{count, number}} <planName/> uygulaması sınırına ulaşıldı. Ekibinizin ihtiyaçlarını karşılamak için ücretli bir plana geçin. Yardıma ihtiyacınız olursa, <a>iletişime geçin</a>.',
'<planName/> limitine ulaşılan {{count, number}} başvuru. Ekibinizin ihtiyaçlarını karşılamak için planı yükseltin. Yardım için lütfen <a>bizimle iletişime geçin</a>.',
applications_other:
'{{count, number}} <planName/> uygulaması sınırına ulaşıldı. Ekibinizin ihtiyaçlarını karşılamak için ücretli bir plana geçin. Yardıma ihtiyacınız olursa, <a>iletişime geçin</a>.',
'<planName/> limitine ulaşılan {{count, number}} başvurular. Ekibinizin ihtiyaçlarını karşılamak için planı yükseltin. Yardım için lütfen <a>bizimle iletişime geçin</a>.',
machine_to_machine_feature:
'Makine-Makine uygulaması oluşturmak için ücretli bir plana geçin ve tüm premium özelliklere erişim sağlayın. Yardıma ihtiyacınız olursa, <a>iletişime geçin</a>.',
'Makine-makine uygulaması oluşturmak ve tüm premium özelliklere erişim sağlamak için ücretli bir plana yükseltin. Yardım için lütfen <a>bizimle iletişime geçin</a>.',
machine_to_machine:
'{{count, number}} <planName/> makine-makine uygulaması sınırına ulaşıldı. Ekibinizin ihtiyaçlarını karşılamak için ücretli bir plana geçin. Yardıma ihtiyacınız olursa, <a>iletişime geçin</a>.',
'<planName/> limitine ulaşılan {{count, number}} makine-makine başvurusu. Ekibinizin ihtiyaçlarını karşılamak için planı yükseltin. Yardım için lütfen <a>bizimle iletişime geçin</a>.',
machine_to_machine_other:
'{{count, number}} <planName/> makine-makine uygulaması sınırına ulaşıldı. Ekibinizin ihtiyaçlarını karşılamak için ücretli bir plana geçin. Yardıma ihtiyacınız olursa, <a>iletişime geçin</a>.',
'<planName/> limitine ulaşılan {{count, number}} makine-makine başvuruları. Ekibinizin ihtiyaçlarını karşılamak için planı yükseltin. Yardım için lütfen <a>bizimle iletişime geçin</a>.',
resources:
'{{count, number}} <planName/> API kaynağı sınırına ulaşıldı. Ekibinizin ihtiyaçlarını karşılamak için planı yükseltin. Yardıma ihtiyacınız olursa, <a>iletişime geçin</a>.',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: '查看',
hide: '隐藏',
unknown_error: '未知错误,请稍后重试。',
select: '选择',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'已达到<planName/>的{{count, number}}个应用程序限制。为满足您团队的需求,请升级到付费计划。如需任何帮助,请随时<a>联系我们</a>。',
'已达到 <planName/> 的{{count, number}}个应用限制。升级计划以满足团队需求。如需帮助,请随时<a>联系我们</a>。',
applications_other:
'已达到<planName/>的{{count, number}}个应用程序限制。为满足您团队的需求,请升级到付费计划。如需任何帮助,请随时<a>联系我们</a>。',
'已达到 <planName/> 的{{count, number}}个应用限制。升级计划以满足团队需求。如需帮助,请随时<a>联系我们</a>。',
machine_to_machine_feature:
'升级到付费计划以创建机器对机器应用程序,同时获得所有高级功能。如需任何帮助,请随时<a>联系我们</a>。',
'升级到付费计划以创建机器对机器应用,并获得所有高级功能的访问权限。如需帮助,请随时<a>联系我们</a>。',
machine_to_machine:
'已达到<planName/>的{{count, number}}个机器对机器应用程序限制。为满足您团队的需求,请升级到付费计划。如需任何帮助,请随时<a>联系我们</a>。',
'已达到 <planName/> 的{{count, number}}个机器对机器应用限制。升级计划以满足团队需求。如需帮助,请随时<a>联系我们</a>。',
machine_to_machine_other:
'已达到<planName/>的{{count, number}}个机器对机器应用程序限制。为满足您团队的需求,请升级到付费计划。如需任何帮助,请随时<a>联系我们</a>。',
'已达到 <planName/> 的{{count, number}}个机器对机器应用限制。升级计划以满足团队需求。如需帮助,请随时<a>联系我们</a>。',
resources:
'已达到<planName/>的{{count, number}}个 API 资源限制。升级计划以满足您团队的需求。<a>联系我们</a>寻求帮助。',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: '查看',
hide: '隱藏',
unknown_error: '未知錯誤,請稍後重試。',
select: '選擇',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'已達到<planName/>的{{count, number}}個應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
applications_other:
'已達到<planName/>的{{count, number}}個應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
machine_to_machine_feature:
'升級到付費計劃以創建機器對機器應用程式,同時獲得所有高級功能。如需任何幫助,請隨時<a>聯繫我們</a>。',
'升級到付費計劃以創建機器對機器應用,並獲得所有高級功能的訪問權限。如需協助,歡迎<a>聯絡我們</a>。',
machine_to_machine:
'已達到<planName/>的{{count, number}}個機器對機器應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個機器對機器應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
machine_to_machine_other:
'已達到<planName/>的{{count, number}}個機器對機器應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個機器對機器應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
resources:
'已達到<planName/>的{{count, number}}個 API 資源限制。升級計劃以滿足您團隊的需求。<a>聯繫我們</a>尋求幫助。',
resources_other:

View file

@ -54,6 +54,7 @@ const general = {
view: '查看',
hide: '隱藏',
unknown_error: '未知錯誤,請稍後重試。',
select: '選擇',
};
export default general;

View file

@ -26,15 +26,15 @@ const upsell = {
},
paywall: {
applications:
'已達到<planName/>的{{count, number}}個應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
applications_other:
'已達到<planName/>的{{count, number}}個應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
machine_to_machine_feature:
'升級到付費計劃以創建機器對機器應用程式,同時獲得所有高級功能。如需任何幫助,請隨時<a>聯繫我們</a>。',
'升級到付費計劃以創建機器對機器應用,並獲得所有高級功能的訪問權限。如需協助,歡迎<a>聯絡我們</a>。',
machine_to_machine:
'已達到<planName/>的{{count, number}}個機器對機器應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個機器對機器應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
machine_to_machine_other:
'已達到<planName/>的{{count, number}}個機器對機器應用程式限制。為滿足您團隊的需求,請升級到付費計劃。如需任何幫助,請隨時<a>聯繫我們</a>。',
'已達到 <planName/> 的{{count, number}}個機器對機器應用程式限制。升級計劃以滿足團隊需求。如需任何協助,歡迎<a>聯絡我們</a>。',
resources:
'已達到<planName/>的{{count, number}}個 API 資源限制。升級計劃以滿足您團隊的需求。<a>聯繫我們</a>尋求幫助。',
resources_other: