diff --git a/README.md b/README.md index 67613d5c1..886b5333d 100644 --- a/README.md +++ b/README.md @@ -666,7 +666,7 @@ NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true Personal accounts are accounts that are owned by a single user. Team accounts are accounts that are owned by multiple users. This allows you to: -1. Server B2C customers (personal accounts) +1. Serve B2C customers (personal accounts) 2. Serve B2B customers (team accounts) 3. Allow both (for example, like GitHub) @@ -696,36 +696,24 @@ NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING=true To enable both, leave them both as `true`. -Please remember that for ensuring DB consistency, you need to also set them at DB level by adjusting the table `config`: - -```sql -create table if not exists public.config( - enable_team_accounts boolean default true not null, - enable_account_billing boolean default true not null, - enable_team_account_billing boolean default true not null, - billing_provider public.billing_provider default 'stripe' not null -); -``` +Please remember that to ensure DB consistency, you need to also set them at DB level by adjusting the table `config`. To enable personal account billing: ```sql -alter table public.config - set enable_account_billing to true; +update config set enable_account_billing = true; ``` To enable team account billing: ```sql -alter table public.config - set enable_team_account_billing to true; +update config set enable_team_account_billing = true; ``` To disable team accounts: ```sql -alter table public.config - set enable_team_accounts to false; +update config set enable_team_accounts = false; ``` To leave them both enabled, just leave them as they are. diff --git a/apps/web/.env b/apps/web/.env index c11631f5e..a34f2aa91 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -43,4 +43,5 @@ NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=true NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION=true NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING=true NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS=true -NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true \ No newline at end of file +NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true +NEXT_PUBLIC_LANGUAGE_PRIORITY=application \ No newline at end of file diff --git a/apps/web/config/feature-flags.config.ts b/apps/web/config/feature-flags.config.ts index 13604b7af..e20ab81c4 100644 --- a/apps/web/config/feature-flags.config.ts +++ b/apps/web/config/feature-flags.config.ts @@ -34,6 +34,12 @@ const FeatureFlagsSchema = z.object({ required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING', }), + languagePriority: z + .enum(['user', 'application'], { + required_error: 'Provide the variable NEXT_PUBLIC_LANGUAGE_PRIORITY', + description: `If set to user, use the user's preferred language. If set to application, use the application's default language.`, + }) + .default('application'), }); const featuresFlagConfig = FeatureFlagsSchema.parse({ @@ -65,6 +71,9 @@ const featuresFlagConfig = FeatureFlagsSchema.parse({ process.env.NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING, false, ), + languagePriority: process.env.NEXT_PUBLIC_LANGUAGE_PRIORITY as + | 'user' + | 'application', } satisfies z.infer); export default featuresFlagConfig; diff --git a/apps/web/lib/i18n/i18n.server.ts b/apps/web/lib/i18n/i18n.server.ts index fab05cfbc..c8b86c567 100644 --- a/apps/web/lib/i18n/i18n.server.ts +++ b/apps/web/lib/i18n/i18n.server.ts @@ -7,6 +7,7 @@ import { parseAcceptLanguageHeader, } from '@kit/i18n/server'; +import featuresFlagConfig from '~/config/feature-flags.config'; import { I18N_COOKIE_NAME, getI18nSettings, @@ -15,6 +16,12 @@ import { import { i18nResolver } from './i18n.resolver'; +/** + * @name priority + * @description The language priority setting from the feature flag configuration. + */ +const priority = featuresFlagConfig.languagePriority; + /** * @name createI18nServerInstance * @description Creates an instance of the i18n server. @@ -24,25 +31,46 @@ import { i18nResolver } from './i18n.resolver'; * Initialize the i18n instance for every RSC server request (eg. each page/layout) */ function createInstance() { - const acceptLanguage = headers().get('accept-language'); const cookie = cookies().get(I18N_COOKIE_NAME)?.value; - let language = - cookie ?? - parseAcceptLanguageHeader(acceptLanguage, languages)[0] ?? - languages[0]; + let selectedLanguage: string | undefined = undefined; + + // if the cookie is set, use the language from the cookie + if (cookie) { + selectedLanguage = getLanguageOrFallback(cookie); + } + + // if not, check if the language priority is set to user and + // use the user's preferred language + if (!selectedLanguage && priority === 'user') { + const userPreferredLanguage = getPreferredLanguageFromBrowser(); + + selectedLanguage = getLanguageOrFallback(userPreferredLanguage); + } + + const settings = getI18nSettings(selectedLanguage); + + return initializeServerI18n(settings, i18nResolver); +} + +export const createI18nServerInstance = cache(createInstance); + +function getPreferredLanguageFromBrowser() { + const acceptLanguage = headers().get('accept-language'); + + return parseAcceptLanguageHeader(acceptLanguage, languages)[0]; +} + +function getLanguageOrFallback(language: string | undefined) { + let selectedLanguage = language; if (!languages.includes(language ?? '')) { console.warn( `Language "${language}" is not supported. Falling back to "${languages[0]}"`, ); - language = languages[0]; + selectedLanguage = languages[0]; } - const settings = getI18nSettings(language); - - return initializeServerI18n(settings, i18nResolver); + return selectedLanguage; } - -export const createI18nServerInstance = cache(createInstance); diff --git a/packages/monitoring/sentry/README.md b/packages/monitoring/sentry/README.md index 34551a07c..747054ce6 100644 --- a/packages/monitoring/sentry/README.md +++ b/packages/monitoring/sentry/README.md @@ -2,7 +2,7 @@ Please set the following environment variable: -``` +```bash NEXT_PUBLIC_MONITORING_PROVIDER=sentry NEXT_PUBLIC_SENTRY_DSN=your_dsn ```