Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions packages/react/src/createServerInstance.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { TolgeeInstance } from '@tolgee/web';
import { createServerInstance } from './createServerInstance';

jest.mock('react', () => ({
...jest.requireActual('react'),
cache: (callback: unknown) => callback,
}));

describe('createServerInstance', () => {
const createTolgeeMock = () => {
const run = jest.fn().mockResolvedValue(undefined);
const t = jest.fn();
const tolgee = { run, t } as unknown as TolgeeInstance;
const createTolgee = jest.fn().mockResolvedValue(tolgee);

return { createTolgee, run, t, tolgee };
};

it('uses the configured locale resolver by default', async () => {
const { createTolgee, run, tolgee } = createTolgeeMock();
const getLocale = jest.fn().mockResolvedValue('en');
const { getTolgee } = createServerInstance({ createTolgee, getLocale });

await expect(getTolgee()).resolves.toBe(tolgee);
expect(getLocale).toHaveBeenCalledTimes(1);
expect(createTolgee).toHaveBeenCalledWith('en');
expect(run).toHaveBeenCalledTimes(1);
});

it('supports an explicit locale parameter object', async () => {
const { createTolgee, tolgee } = createTolgeeMock();
const getLocale = jest.fn().mockResolvedValue('en');
const { getTolgee } = createServerInstance({ createTolgee, getLocale });

await expect(getTolgee({ locale: 'cs' })).resolves.toBe(tolgee);
expect(getLocale).not.toHaveBeenCalled();
expect(createTolgee).toHaveBeenCalledWith('cs');
});

it('passes an explicit locale parameter object to translations', async () => {
const { createTolgee, t } = createTolgeeMock();
const getLocale = jest.fn().mockResolvedValue('en');
const { getTranslate } = createServerInstance({ createTolgee, getLocale });

await expect(getTranslate({ locale: 'cs' })).resolves.toBe(t);
expect(getLocale).not.toHaveBeenCalled();
expect(createTolgee).toHaveBeenCalledWith('cs');
});

it('supports an explicit locale in the server T component', async () => {
const { createTolgee } = createTolgeeMock();
const getLocale = jest.fn().mockResolvedValue('en');
const { T } = createServerInstance({ createTolgee, getLocale });

await T({ keyName: 'hello', locale: 'cs' });

expect(getLocale).not.toHaveBeenCalled();
expect(createTolgee).toHaveBeenCalledWith('cs');
});
});
22 changes: 15 additions & 7 deletions packages/react/src/createServerInstance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export type CreateServerInstanceOptions = {
getLocale: () => Promise<string>;
};

type ServerTProps = TProps & {
locale?: string;
};

type ServerFunctionOptions = {
locale?: string;
};

export const createServerInstance = ({
createTolgee,
getLocale,
Expand All @@ -24,19 +32,19 @@ export const createServerInstance = ({
}
);

const getTolgee = async () => {
const locale = await getLocale();
const tolgee = await getTolgeeInstance(locale);
const getTolgee = async ({ locale }: ServerFunctionOptions = {}) => {
const resolvedLocale = locale ?? (await getLocale());
const tolgee = await getTolgeeInstance(resolvedLocale);
return tolgee;
};

const getTranslate = async () => {
const tolgee = await getTolgee();
const getTranslate = async ({ locale }: ServerFunctionOptions = {}) => {
const tolgee = await getTolgee({ locale });
return tolgee.t;
};

async function T(props: TProps) {
const t = await getTranslate();
async function T({ locale, ...props }: ServerTProps) {
const t = await getTranslate({ locale });
return <TBase t={t as TFnType<ParamsTags>} {...props} />;
}

Expand Down
14 changes: 14 additions & 0 deletions testapps/next-app-intl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,17 @@ NEXT_PUBLIC_TOLGEE_API_KEY=<your project API key>
```

6. Re-run `npm run dev`

## Static rendering

When the locale is already available from route params, pass it directly to
`getTolgee`:

```tsx
const { locale } = await params;
const tolgee = await getTolgee({ locale });
```

This avoids running the configured request locale resolver during static
generation. The `/[locale]/ssg` route demonstrates this with
`generateStaticParams`.
2 changes: 1 addition & 1 deletion testapps/next-app-intl/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default async function LocaleLayout({ children, params }: Props) {
if (!ALL_LANGUAGES.includes(locale)) {
notFound();
}
const tolgee = await getTolgee();
const tolgee = await getTolgee({ locale });
const records = await tolgee.loadRequired();

return (
Expand Down
11 changes: 11 additions & 0 deletions testapps/next-app-intl/src/app/[locale]/ssg/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ALL_LANGUAGES } from '@/tolgee/shared';

export const dynamic = 'error';

export function generateStaticParams() {
return ALL_LANGUAGES.map((locale) => ({ locale }));
}

export default function StaticPage() {
return <div>Static page</div>;
}