From 8f62243908275a5f6baf4afd6df8134de3c3567f Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Thu, 18 Jan 2024 13:57:26 +0100 Subject: [PATCH 01/10] fix: New pricing -> blog post --- blog/2024-01-18-announcing-new-pricing.mdx | 167 +++++++++++++ blog/authors.yml | 6 +- src/component/pricing/PricingChanges.tsx | 46 ++++ src/component/table/Table.tsx | 49 ++++ src/css/custom.css | 269 +++++++++++---------- src/custom.d.ts | 12 + src/theme/LayoutContent.tsx | 17 +- src/theme/colors.ts | 12 + src/theme/muiTheme.tsx | 13 + static/img/blog/new-pricing.webp | Bin 0 -> 33418 bytes 10 files changed, 439 insertions(+), 152 deletions(-) create mode 100644 blog/2024-01-18-announcing-new-pricing.mdx create mode 100644 src/component/pricing/PricingChanges.tsx create mode 100644 src/component/table/Table.tsx create mode 100644 src/theme/colors.ts create mode 100644 src/theme/muiTheme.tsx create mode 100644 static/img/blog/new-pricing.webp diff --git a/blog/2024-01-18-announcing-new-pricing.mdx b/blog/2024-01-18-announcing-new-pricing.mdx new file mode 100644 index 000000000..d91fab055 --- /dev/null +++ b/blog/2024-01-18-announcing-new-pricing.mdx @@ -0,0 +1,167 @@ +--- +slug: new-pricing-2024-01 +title: "Upcoming Changes to Tolgee's Pricing Plans" +description: "We are making some changes to Tolgee's pricing plans. Read more about the changes and the reasons behind them." +authors: [jcizmar] +tags: ['tolgee', 'pricing'] +image: '/img/blog/content-delivery/content-delivery.webp' +--- + +import { PricingChanges } from "../src/component/pricing/PricingChanges"; + +Dear Tolgee Users, + +In the past year of 2023, Tolgee made a significant step forward, introducing many new features and making the whole +project more robust. We must reflect these company and product developments into the pricing to align with the new product state and the company's business targets. + +![Image](/img/blog/new-pricing.webp) + + + +## What do we change? + + - We are entirely redesigning the pay-as-you-go plan + - We are adding a new, more accessible "Team" plan for self-hosted instances + - We are making the Tolgee AI Translator available also on self-hosted instances + - We are limiting the number of seats in the self-hosted free plan + - We are making machine translation credits way cheaper + - The new plans will be available by **26th January 2024** + +## What is changing in Cloud pricing + +Until now, we have considered the re-selling of +machine translation as one of our core revenue streams. The experience showed us that this wasn't the right decision. +We want to keep machine translation accessible for all our customers, and we don't want to discourage new customers +with high machine translation prices. At the same time, we would like to focus on improving the Tolgee AI translator +so it's used by as many customers as possible because we see unlimited opportunities in AI. The new price +of 1000 machine translation credits will be unified at €0.035 per 1000 machine translation credits in all the plans, +including the self-hosted ones. We will also charge one machine translation credit per character for the Tolgee AI translator. +While before, we were charging you 10 MT credits per OpenAI token, +which made our pricing more complex than required. Overall, +we are making our pricing simpler to understand and more straightforward. + +We are also completely redesigning the pay-as-you-go plan. The past year showed us that providing the plan, +starting at 0€ and charging only for what's consumed, isn't cost-effective for us. For many pay-as-you-go customers, +the payment processing and related costs are higher than the actual revenue. So the new plan will start at €30, which +we consider a fair minimal price for the service. The new plan will contain new features such as the Webhooks +and Custom Content Delivery Storage. + +### The Pay-as-you-go plan changes + + + +The current pay-as-you-go plan users will be transferred to the updated pay-as-you-go plan on March 1st. +Please get in touch with us if you have any concerns about this change using any of the channels described at +the bottom of this post. + +### The Business plan changes + + + +### For open-source projects + +As an open-source project, you don't have to worry; we still provide the free business plan on the Tolgee Cloud. + +## What is changing in self-hosted pricing + +We discovered that Tolgee provides great value for many companies that use Tolgee on self-hosted instances, but very few +of them actually subscribed to our "Bussiness" plan. According to our analysis, the free plan is also sufficient for +larger teams of 10+ developers, and the price of the business plan is too high while not bringing much more value. + +Because of this, we decided to make the Tolgee AI translator available also to customers who purchased a license +for any of the self-hosted plans. This way, the self-hosted license brings significant benefits in comparison +to the free plan. We are also adding a new, more cost-effective "Team" plan. At the same time, we decided to limit the +number of seats in the free plan to 10. This change won't affect the users on older Tolgee Platform versions, so +the users staying with such versions are fine with continuing with the previous unlimited free plan. + +The new version of the Tolgee platform with limited free users will be released by January 26th. + +### The new Team plan on Self-hosted + + + Price per 1000 MT credits
(Only or Tolgee Translator services, for other services, you can provide your + own API key) + , + oldValue: "N/A", + newValue: "€0.035" + }, + { + item: "Additional features", + oldValue: "N/A", + newValue: "Webhooks, Multiple content delivery configs, Tolgee AI translator" + }, +]} /> + +### Changes to Business plan on self-hosted + + + Price per 1000 MT credits
(Only or Tolgee Translator services, for other services, you can provide your + own API key) + , + oldValue: "N/A", + newValue: "€0.035" + }, + { + item: "Additional features", + oldValue: "N/A", + newValue: "Tolgee AI translator" + }, +]} /> + +We understand that this change might be hard to accept for many companies using Tolgee for free on self-hosted instances. +We apologize for the inconvenience you may encounter. However, we need to focus on making the company stable +and cost-effective, and we want to assure you that additional revenues from this change will be used +for future product development, bringing you great new features like GitHub/GitLab integrations, Visual Editor, +Universal Format Support, Mobile SDKs, Document translations and much more. We thank you in advance for understanding. + +## Few more words to advocate the changes + +When we started Tolgee in 2020, our goal was simple: to create an open-source localization platform that makes the +translation process easier for software developers. Today, we are proud to see thousands of +users and hundreds of companies actively using Tolgee. + +Over the past three years, we have personally invested a significant amount of our time and resources into the +development and growth of Tolgee, funded primarily through our personal investments. +This journey has been enriching, brimming with learning opportunities, rewards, and the pure +enjoyment of working diligently on a tool that we are passionate about. Moreover, the positive feedback and +warm reactions we have received from our users have only amplified our excitement and commitment to this project. + +In 2024, we are facing the reality of the current market situation and recognizing that it is time for us to think +about long-term sustainability and company stability. Until now, we have provided many features that deliver value +to many companies while only a fraction contribute to future development by subscribing to non-free subscription plans. +We realized this has to change if Tolgee should become a stable and sustainable company. + +I understand and empathize that these changes may cause discomfort and may not accommodate everyone's circumstances. +It this materially impacts your business, I warmly invite +you to contact me directly. I am open to having a personal dialogue regarding your concerns, and I am firmly committed +to exploring potential solutions with you to continue providing a platform that satisfies and comforts your +experience with us. You can get in touch with me directly + - at jan@tolgee.io + - in the Tolgee slack community at https://tolg.ee/slack + - or book a slot in my Calendly at https://tolg.ee/jan. diff --git a/blog/authors.yml b/blog/authors.yml index d5c5beef7..e2fffaa47 100644 --- a/blog/authors.yml +++ b/blog/authors.yml @@ -1,13 +1,13 @@ sgranat: name: Štěpán Granát - title: Co-founder and CTO + title: Co-founder & CTO & The front-end magician url: https://github.com/stepan662 image_url: /img/blog/profile-photos/stepan.jpeg description: "Štěpán is a passionate developer responsible for Frontend and SDK development at Tolgee. He's on a mission to make software localization as easy as pie while keeping it smart. 🧠" jcizmar: - name: Jan Cizmar 😎 - title: Founder & Full-stack Architect + name: Jan Cizmar 🧑🏻‍💻 + title: CEO & Full-stack Architect url: https://github.com/JanCizmar image_url: /img/blog/profile-photos/jan.jpeg description: "Jan is a coding mastermind who's on a mission to save the world from software localization chaos. He has a passion for clean code, hates being a copy-pasting monkey 🙈 and is dedicated to delivering smart and simple software as the head of Tolgee." diff --git a/src/component/pricing/PricingChanges.tsx b/src/component/pricing/PricingChanges.tsx new file mode 100644 index 000000000..48849c2a2 --- /dev/null +++ b/src/component/pricing/PricingChanges.tsx @@ -0,0 +1,46 @@ +import React, { FC, ReactNode } from 'react'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeadCell, + TableRow, +} from '../table/Table'; +import clsx from 'clsx'; + +export type PricingChangesData = [ + { + item: ReactNode; + isNumber?: boolean; + oldValue: ReactNode; + newValue: ReactNode; + } +]; + +export const PricingChanges: FC<{ data: PricingChangesData }> = (props) => { + return ( + + + + + Old + New + + + + {props.data.map((row, index) => ( + + {row.item} + + {row.oldValue} + + + {row.newValue} + + + ))} + +
+ ); +}; diff --git a/src/component/table/Table.tsx b/src/component/table/Table.tsx new file mode 100644 index 000000000..854573b69 --- /dev/null +++ b/src/component/table/Table.tsx @@ -0,0 +1,49 @@ +import { styled } from '@mui/material'; +import React, { FC } from 'react'; + +export const TableInner = styled('table')` + display: table; +`; + +export const TableContainer = styled('div')` + border-radius: 4px; + border: 1px solid ${(props) => props.theme.palette.custom.tableBorder}; + overflow: auto; + display: inline-block; +`; + +export const Table: FC = (props) => { + return ( + + {props.children} + + ); +}; + +export const TableHead = styled('thead')` + background-color: ${(props) => + props.theme.palette.custom.tableHeadBackground}; + color: ${(props) => props.theme.palette.primary.main}; + border: 0; + + tr { + border-bottom: 1px solid ${(props) => + props.theme.palette.custom.tableBorder}; + } +} +`; + +export const TableBody = styled('tbody')``; + +export const TableRow = styled('tr')` + border: 0; +`; + +export const TableCell = styled('td')` + border: 0; + background-color: ${(props) => props.theme.palette.custom.tableRowBackground}; +`; + +export const TableHeadCell = styled('th')` + border: 0; +`; diff --git a/src/css/custom.css b/src/css/custom.css index 2c8bfcfc9..0319fbe87 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -11,122 +11,124 @@ /* You can override the default Infima variables here. */ :root { - --ifm-color-primary: #ec407a; - --ifm-color-primary-dark: #ec407a; - --ifm-color-primary-darker: #da3c71; - --ifm-color-primary-darkest: #cc3467; - --ifm-color-primary-light: #ec477e; - --ifm-color-primary-lighter: #ec5286; - --ifm-color-primary-lightest: #ef5f8f; - --ifm-code-font-size: 95%; - --ifm-font-family-base: Roboto, Arial, sans-serif; - --gradient-start-color: var(--ifm-color-emphasis-200); - --gradient-main-color: var(--ifm-background-color); - --ifm-background-color: rgb(255, 255, 255); - --ifm-background-surface-color: #f8f9fa; - --overlay-background: rgba(255, 255, 255, 0.9); - --page-decoration-color: rgba(255, 255, 255); - --emphasis-gradient-start: var(--ifm-color-primary-darkest); - --emphasis-gradient-end: var(--ifm-color-primary-lighter); - --light-home-text: #546074; - --dark-home-text: #e0e4ea; - --navbar-link-text-color: #303846; - --home-text: var(--light-home-text); - --text-secondary: #4e4d4d; - --home-features-gradient-1: #ebedf0; - --home-features-gradient-2: #ebedf0; - --home-features-gradient-3: #ffffff; - --references-bg: #eeeef0; - --footer-background-gradient-start: #ffffff; - --footer-background-gradient-stop: #ebedf0; - --ifm-navbar-background-color-transparent: #f8f9facc; + --ifm-color-primary: #ec407a; + --ifm-color-primary-dark: #ec407a; + --ifm-color-primary-darker: #da3c71; + --ifm-color-primary-darkest: #cc3467; + --ifm-color-primary-light: #ec477e; + --ifm-color-primary-lighter: #ec5286; + --ifm-color-primary-lightest: #ef5f8f; + --ifm-code-font-size: 95%; + --ifm-font-family-base: Roboto, Arial, sans-serif; + --gradient-start-color: var(--ifm-color-emphasis-200); + --gradient-main-color: var(--ifm-background-color); + --ifm-background-color: rgb(255, 255, 255); + --ifm-background-surface-color: #f8f9fa; + --overlay-background: rgba(255, 255, 255, 0.9); + --page-decoration-color: rgba(255, 255, 255); + --emphasis-gradient-start: var(--ifm-color-primary-darkest); + --emphasis-gradient-end: var(--ifm-color-primary-lighter); + --light-home-text: #546074; + --dark-home-text: #e0e4ea; + --navbar-link-text-color: #303846; + --home-text: var(--light-home-text); + --text-secondary: #4e4d4d; + --home-features-gradient-1: #ebedf0; + --home-features-gradient-2: #ebedf0; + --home-features-gradient-3: #ffffff; + --references-bg: #eeeef0; + --footer-background-gradient-start: #ffffff; + --footer-background-gradient-stop: #ebedf0; + --ifm-navbar-background-color-transparent: #f8f9facc; + --table-border-color: #D1D6DC } html[data-theme='dark'] { - --ifm-color-primary: rgb(255, 105, 149); - --ifm-color-primary-dark: #e55e86; - --ifm-color-primary-darker: #db5e83; - --ifm-color-primary-darkest: #c45374; - --ifm-color-primary-light: #e7668c; - --ifm-color-primary-lighter: #ea7497; - --ifm-color-primary-lightest: #ec84a3; - --ifm-background-color: #182230; - --ifm-background-surface-color: #1f2d40; - --gradient-start-color: #1f2d40; - --gradient-main-color: #182230; - --overlay-background: rgba(0, 0, 0, 0.9); - --docsearch-hit-active-color: rgb(0, 0, 0); - --page-decoration-color: #0c121a; - --emphasis-gradient-start: var(--ifm-color-primary-lighter); - --emphasis-gradient-end: var(--ifm-color-primary-dark); - --navbar-link-text-color: var(--dark-home-text); - --home-text: var(--dark-home-text); - --text-secondary: #cccbcb; - --home-features-gradient-1: var(--gradient-start-color); - --home-features-gradient-2: var(--gradient-start-color); - --home-features-gradient-3: #253852; - --references-bg: #253852; - --footer-background-gradient-start: var(--ifm-background-color); - --footer-background-gradient-stop: var(--overlay-background); - --ifm-navbar-background-color-transparent: #1f2d40cc; + --ifm-color-primary: rgb(255, 105, 149); + --ifm-color-primary-dark: #e55e86; + --ifm-color-primary-darker: #db5e83; + --ifm-color-primary-darkest: #c45374; + --ifm-color-primary-light: #e7668c; + --ifm-color-primary-lighter: #ea7497; + --ifm-color-primary-lightest: #ec84a3; + --ifm-background-color: #182230; + --ifm-background-surface-color: #1f2d40; + --gradient-start-color: #1f2d40; + --gradient-main-color: #182230; + --overlay-background: rgba(0, 0, 0, 0.9); + --docsearch-hit-active-color: rgb(0, 0, 0); + --page-decoration-color: #0c121a; + --emphasis-gradient-start: var(--ifm-color-primary-lighter); + --emphasis-gradient-end: var(--ifm-color-primary-dark); + --navbar-link-text-color: var(--dark-home-text); + --home-text: var(--dark-home-text); + --text-secondary: #cccbcb; + --home-features-gradient-1: var(--gradient-start-color); + --home-features-gradient-2: var(--gradient-start-color); + --home-features-gradient-3: #253852; + --references-bg: #253852; + --footer-background-gradient-start: var(--ifm-background-color); + --footer-background-gradient-stop: var(--overlay-background); + --ifm-navbar-background-color-transparent: #1f2d40cc; + --table-border-color: rgba(43, 60, 84, 0.8) } *[itemprop='headline'] { - font-size: 2rem !important; + font-size: 2rem !important; } body { - max-width: 100vw; + max-width: 100vw; } /*noinspection CssUnresolvedCustomProperty*/ .docusaurus-highlight-code-line { - background-color: rgb(72, 77, 91); - display: block; - margin: 0 calc(-1 * var(--ifm-pre-padding)); - padding: 0 var(--ifm-pre-padding); + background-color: rgb(72, 77, 91); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); } .tagline__weapon-wrapper { - display: inline-block; - background: rgba(177, 177, 177, 0.24); - padding: 4px; - position: relative; - width: 120px; - border-radius: 10px; - margin-left: 10px; - overflow: hidden; - font-family: monaco, 'andale mono', 'lucida console', 'courier new', monospace; + display: inline-block; + background: rgba(177, 177, 177, 0.24); + padding: 4px; + position: relative; + width: 120px; + border-radius: 10px; + margin-left: 10px; + overflow: hidden; + font-family: monaco, 'andale mono', 'lucida console', 'courier new', monospace; } .button--outline { - border-width: 1px; - border-style: solid; + border-width: 1px; + border-style: solid; } .home__container { - background-color: var(--gradient-main-color); + background-color: var(--gradient-main-color); } .footer { - position: relative; - z-index: 4; + position: relative; + z-index: 4; } .navbar { - color: var(--navbar-link-text-color); + color: var(--navbar-link-text-color); } .navbar__link { - font-weight: normal; + font-weight: normal; } .navbar .DocSearch { - display: none; + display: none; } .sidebar-search .DocSearch.DocSearch-Button { - width: 100%; + width: 100%; } h1, @@ -135,136 +137,135 @@ h3, h4, h5, h6 { - font-weight: 500; + font-weight: 500; } .menu { - font-weight: 400; + font-weight: 400; } .docusaurus-mt-lg { - margin-top: 3rem; + margin-top: 3rem; } .footer { - background: linear-gradient( - 180deg, - var(--footer-background-gradient-start), - var(--footer-background-gradient-stop) - ); + background: linear-gradient( + 180deg, + var(--footer-background-gradient-start), + var(--footer-background-gradient-stop) + ); } .footer__title, .footer__link-item { - color: var(--home-text); + color: var(--home-text); } .hero-svg { - width: 100%; - overflow: visible; - height: unset; + width: 100%; + overflow: visible; + height: unset; } .navbar { - padding: 0px; - background-color: transparent; + padding: 0px; + background-color: transparent; } .navbar__inner { - padding: var(--ifm-navbar-padding-vertical) - var(--ifm-navbar-padding-horizontal); - backdrop-filter: saturate(180%) blur(8px); - background-color: var(--ifm-navbar-background-color-transparent); - height: var(--ifm-navbar-height); - transition: background-color 0.3s; + padding: var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal); + backdrop-filter: saturate(180%) blur(8px); + background-color: var(--ifm-navbar-background-color-transparent); + height: var(--ifm-navbar-height); + transition: background-color 0.3s; } .navbar__brand:hover { - color: inherit; + color: inherit; } .navbar__title { - font-family: Righteous, Arial, sans-serif; - font-weight: 500; - font-size: 18px; - color: #2c3c52; + font-family: Righteous, Arial, sans-serif; + font-weight: 500; + font-size: 18px; + color: #2c3c52; } html[data-theme='dark'] .navbar__title { - color: unset; + color: unset; } .navbar .dropdown__menu { - display: grid; - grid-auto-flow: column; - padding: 12px; - gap: 16px; + display: grid; + grid-auto-flow: column; + padding: 12px; + gap: 16px; } .navbar .dropdown__menu-group { - list-style-type: none; - padding-left: 0; - margin-bottom: 0; + list-style-type: none; + padding-left: 0; + margin-bottom: 0; } .navbar .dropdown__menu-title { - font-size: 0.73rem; - text-transform: uppercase; - padding: 6px 8px; - color: var(--text-secondary); + font-size: 0.73rem; + text-transform: uppercase; + padding: 6px 8px; + color: var(--text-secondary); } .navbar .navbar__link::after, .sidebar-version-dropdown .navbar__link::after { - border-width: 0px 0px 2px 2px; - border-color: currentColor; - width: 5px; - height: 5px; - transform: rotate(-45deg) translate(50%, -50%); - margin-left: 6px; + border-width: 0px 0px 2px 2px; + border-color: currentColor; + width: 5px; + height: 5px; + transform: rotate(-45deg) translate(50%, -50%); + margin-left: 6px; } .row .footer__col { - @apply px-5; + @apply px-5; } .sidebar-version-dropdown { - @apply py-2 flex justify-center flex-col; + @apply py-2 flex justify-center flex-col; } .navbar__item .navbar__link { - @apply flex justify-between items-center; + @apply flex justify-between items-center; } .dropdown__dropdown-label { - @apply text-gray-500 text-[15px]; + @apply text-gray-500 text-[15px]; } .sidebar-version-dropdown .dropdown__menu { - @apply w-full; + @apply w-full; } .dropdown__label-wrapper { - @apply flex justify-between grow items-center; + @apply flex justify-between grow items-center; } .sidebar-version-dropdown .navbar__item { - @apply py-0 px-0 mt-[-2px]; + @apply py-0 px-0 mt-[-2px]; } .sidebar-version-dropdown .navbar__item .navbar__link { - display: flex; + display: flex; } .sidebar-version-dropdown .navbar__item { - @apply flex flex-col; + @apply flex flex-col; } .sidebar-version-dropdown { - @apply border-0 border-b border-solid border-gray-100 mx-3 mb-4; + @apply border-0 border-b border-solid border-gray-100 mx-3 mb-4; } .sidebar-version-dropdown ul { - list-style: none; - padding: 0; + list-style: none; + padding: 0; } diff --git a/src/custom.d.ts b/src/custom.d.ts index 006534e23..ad06f3f48 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -1,4 +1,16 @@ +import { CustomThemeColors } from './theme/colors'; + declare module '*.svg' { const content: React.FunctionComponent>; export default content; } + +declare module '@mui/material/styles' { + interface Palette { + custom: CustomThemeColors; + } + + interface PaletteOptions { + custom: CustomThemeColors; + } +} diff --git a/src/theme/LayoutContent.tsx b/src/theme/LayoutContent.tsx index e061c3144..a1200fc8c 100644 --- a/src/theme/LayoutContent.tsx +++ b/src/theme/LayoutContent.tsx @@ -6,13 +6,13 @@ import { getChatwootScript } from '../component/externalScripts/getChatwootScrip import { getGtagScript } from '../component/externalScripts/getGtagScript'; import websiteSchema from '../info/website'; import { - createTheme, Experimental_CssVarsProvider, ThemeProvider as MuiThemeProvider, useColorScheme, } from '@mui/material'; import { useDarkMode } from '../utils'; import { getHotjarScript } from '../component/externalScripts/getHotjarScript'; +import { createTheme } from './muiTheme'; const MuiThemeSynchronizer = () => { const isDarkTheme = useDarkMode(); @@ -48,25 +48,12 @@ export const LayoutContent = ({ children }) => { }, [isDarkTheme]); const theme = useMemo(() => { - return createTheme({ - palette: { - primary: { - main: isDarkTheme ? 'rgb(255, 105, 149)' : '#EC407A', - }, - }, - }); + return createTheme(isDarkTheme); }, [isDarkTheme]); return ( <> - {/*{cookieYesId && (*/} - {/* */} - {/*)}*/} {trackingId && (