From 5214de03fae456be68cab922ba21f6ed16661cf0 Mon Sep 17 00:00:00 2001 From: Ernest McCarter Date: Fri, 3 Jul 2026 15:32:31 -0700 Subject: [PATCH 1/3] docs: update documentation for the odysseus major release Updates docs and templates to match the odysseus release across gt-next, gt-react, gt-react-native, gt-tanstack-start, gt-node, gt-i18n, and generaltranslation. All changes verified against the odysseus branch source. - gt-next: remove gt-next/client, trim gt-next/server to server-only exports, GTProvider props reduced to children, env-var-only credentials, renderSettings timeout-only, headers/cookies config, new page, Cache Components requirements, SSG cleanup - gt-react: initializeGT()/initializeGTSPA() setup, GTProvider requires locale + translations snapshot, no loading states, Vite env credentials - gt-react-native: named plugin export, initializeGT in app entry, GTProvider fallback prop, quickstart fixes - gt-tanstack-start: getTranslationsSnapshot(locale) + parseLocale loader flow, re-exported gt-react surface - Types: InlineTranslationOptions -> GTTranslationOptions, DictionaryTranslationOptions -> TranslationVariables (slugs kept), $context/$locale sugar options - Dictionary miss now throws for missing default-locale entries; missing target-locale translations fall back to source - id no longer affects the translation hash - CLI/compiler: legacyGtReactImportSource parsing flag Co-Authored-By: Claude Fable 5 --- docs-templates/api/components/t.mdx | 19 +- docs-templates/api/config/gt-config-json.mdx | 3 +- docs-templates/api/config/load-dictionary.mdx | 27 +- .../api/config/load-translations.mdx | 16 +- .../api/dictionary/use-translations.mdx | 43 ++- docs-templates/api/strings/msg.mdx | 2 +- docs-templates/api/strings/use-gt.mdx | 19 +- docs-templates/api/strings/use-messages.mdx | 21 +- .../types/dictionary-translation-options.mdx | 36 ++- .../api/types/inline-translation-options.mdx | 59 +++- docs-templates/concepts/environments.mdx | 18 +- docs-templates/guides/dictionaries.mdx | 58 ++-- docs-templates/guides/local-tx.mdx | 19 +- docs-templates/guides/migration.mdx | 27 +- docs-templates/guides/strings.mdx | 2 +- docs-templates/reference/gt-jsx.mdx | 13 +- .../en-US/cli/features/auto-jsx-injection.mdx | 2 + docs/en-US/cli/reference/config.mdx | 30 +++ docs/en-US/core/class/constructor.mdx | 1 + docs/en-US/core/index.mdx | 21 ++ docs/en-US/next/api/components/gtprovider.mdx | 46 +--- docs/en-US/next/api/components/link.mdx | 96 +++++++ docs/en-US/next/api/components/meta.json | 1 + docs/en-US/next/api/components/t.mdx | 13 +- docs/en-US/next/api/components/tx.mdx | 6 +- .../en-US/next/api/config/load-dictionary.mdx | 10 + .../next/api/config/load-translations.mdx | 9 +- docs/en-US/next/api/config/with-gt-config.mdx | 133 +++++---- .../next/api/dictionary/get-translations.mdx | 20 +- .../next/api/dictionary/use-translations.mdx | 33 ++- .../next/api/helpers/get-default-locale.mdx | 15 +- .../api/helpers/get-locale-properties.mdx | 14 +- docs/en-US/next/api/helpers/get-locales.mdx | 14 +- .../next/api/helpers/is-locale-supported.mdx | 13 +- docs/en-US/next/api/strings/get-gt.mdx | 4 +- docs/en-US/next/api/strings/get-messages.mdx | 12 +- .../types/dictionary-translation-options.mdx | 50 +++- .../api/types/inline-translation-options.mdx | 48 +++- .../api/types/runtime-translation-options.mdx | 1 + docs/en-US/next/concepts/environments.mdx | 10 +- docs/en-US/next/guides/cache-components.mdx | 25 +- docs/en-US/next/guides/dictionaries.mdx | 6 +- docs/en-US/next/guides/dynamic-content.mdx | 9 +- docs/en-US/next/guides/languages.mdx | 8 +- docs/en-US/next/guides/locale-aliases.mdx | 10 +- docs/en-US/next/guides/ssg.mdx | 7 +- .../next/tutorials/translating-strings.mdx | 8 +- docs/en-US/node/api/get-gt.mdx | 6 +- docs/en-US/node/api/get-messages.mdx | 4 +- docs/en-US/node/api/get-translations.mdx | 16 +- docs/en-US/node/api/initialize-gt.mdx | 18 +- docs/en-US/node/api/strings/msg.mdx | 2 +- .../api/components/gtprovider.mdx | 236 +++++++--------- .../helpers/get-locale-from-native-store.mdx | 4 +- .../types/dictionary-translation-options.mdx | 4 +- .../api/types/inline-translation-options.mdx | 4 +- docs/en-US/react-native/faqs.mdx | 2 +- .../react-native/tutorials/mini-shop.mdx | 56 +++- .../tutorials/quickstart-expo.mdx | 59 ++-- .../react-native/tutorials/quickstart.mdx | 48 ++-- .../en-US/react/api/components/gtprovider.mdx | 255 ++++++------------ docs/en-US/react/api/strings/t-function.mdx | 232 ++++++---------- .../types/dictionary-translation-options.mdx | 4 +- .../api/types/inline-translation-options.mdx | 4 +- docs/en-US/react/concepts/compiler.mdx | 30 +++ docs/en-US/react/faqs.mdx | 4 +- docs/en-US/react/index.mdx | 95 ++++--- docs/en-US/react/tutorials/mini-shop.mdx | 39 ++- docs/en-US/tanstack-start/index.mdx | 23 +- docs/en-US/tanstack-start/introduction.mdx | 20 +- 70 files changed, 1246 insertions(+), 976 deletions(-) create mode 100644 docs/en-US/next/api/components/link.mdx diff --git a/docs-templates/api/components/t.mdx b/docs-templates/api/components/t.mdx index eef60f1a..257d0907 100644 --- a/docs-templates/api/components/t.mdx +++ b/docs-templates/api/components/t.mdx @@ -38,9 +38,10 @@ Make sure to follow the [deployment guide here](__DOCS_PATH__/tutorials/quickdep type: 'any', optional: false, }, - "id": { + "id?": { type: 'string', - optional: false, + optional: true, + default: 'undefined', }, "context?": { type: 'string', @@ -59,14 +60,14 @@ Make sure to follow the [deployment guide here](__DOCS_PATH__/tutorials/quickdep | Prop | Description | |-----------------|-------------------------------------------------------------------------------------------------| | `children` | The content to be translated. This can include plain text or JSX structures. | -| `id` | A unique identifier for the translation string. This ensures consistent translation across your app. | +| `id` | An optional identifier for the translation, sent to the GT platform as descriptive metadata. It does not affect how translations are looked up. | | `context` | Additional context to refine the translation. Useful for resolving ambiguous phrases. | | `requiresReview` | When `true`, the translation is withheld from serving until it is approved in a human-review step. Must be a boolean literal. `$requiresReview` is an equivalent alias. | ### Returns -`React.JSX.Element|undefined` which contains the rendered translation or fallback content based on the provided configuration. +`React.JSX.Element|undefined` which contains the rendered translation, or the source content when no translation is available. --- @@ -83,12 +84,13 @@ If a translation is not found, it will fallback to the original content. Make sure to follow the [deployment guide here](__DOCS_PATH__/tutorials/quickdeploy). ### Development -During development, the `` function will translate content on demand. +During development, the `` component will translate content on demand. This is useful for prototyping what your app will look like in different languages. Remember to add a Dev API key to your environment to enable this behavior. -While loading, `` will return undefined unless languages are similar (en-US vs en-GB), though this behavior can be customized with render settings. -If an error occurs, `` will return the original content. +`` renders synchronously from the loaded translation snapshot. +While an updated translation is loading during hot reload, `` keeps showing the previous output. +If no translation is available, `` renders the original content. You will see a delay during on-demand translation in development. This delay will not occur in production builds as everything will already be translated. @@ -99,7 +101,7 @@ This delay will not occur in production builds as everything will already be tra ### Basic usage -The `` component can translate simple strings using an `id` and its children. +The `` component translates its children. Remember, the `` component must be used inside a [``](__DOCS_PATH__/api/components/gtprovider) to access the translations. ```jsx title="SimpleTranslation.jsx" copy @@ -218,6 +220,7 @@ export default function Example() { * The `` component is designed for translating content in your application. It is the primary method for localization in `__PACKAGE_NAME__`. * Use the `` component to translate plain text or JSX structures, including variables and pluralization. * Ensure the `` component is wrapped in a [``](__DOCS_PATH__/api/components/gtprovider) to access the translation context. + * Translations are looked up by a hash computed from the message content plus `context` and `maxChars` (and review metadata). The `id` prop does not change this hash; it is descriptive metadata sent to the GT platform. * The `requiresReview` prop only accepts a boolean literal. Only the value `true` changes the content hash and withholds the translation until it is approved. ## Next steps diff --git a/docs-templates/api/config/gt-config-json.mdx b/docs-templates/api/config/gt-config-json.mdx index dd1df53d..0acfb80e 100644 --- a/docs-templates/api/config/gt-config-json.mdx +++ b/docs-templates/api/config/gt-config-json.mdx @@ -66,7 +66,8 @@ The `files.gt.parsingFlags` object controls how the compiler parses your source | Flag | Type | Default | Description | |------|------|---------|-------------| | `enableAutoJsxInjection` | `boolean` | `false` | Automatically wrap translatable JSX text in translation components at build time. See [auto JSX injection](/docs/cli/features/auto-jsx-injection). | -| `autoderive` | `boolean` | `false` | Automatically treat interpolated values in `t()`, `gt()`, and `msg()` calls as [`derive()`](__DOCS_PATH__/api/strings/derive) calls. See [autoderive](/docs/cli/features/autoderive). | +| `autoderive` | `boolean \| { jsx?: boolean; strings?: boolean }` | `false` | Automatically treat interpolated values in `t()`, `gt()`, and `msg()` calls as [`derive()`](__DOCS_PATH__/api/strings/derive) calls. Pass an object to enable it selectively for JSX or strings. See [autoderive](/docs/cli/features/autoderive). | +| `legacyGtReactImportSource` | `boolean` | `false` | Emit compiler-injected imports from `gt-react/browser` instead of `gt-react`, for compatibility with older `gt-react` majors. | ```json title="gt.config.json" { diff --git a/docs-templates/api/config/load-dictionary.mdx b/docs-templates/api/config/load-dictionary.mdx index e8438ae5..aeedaed1 100644 --- a/docs-templates/api/config/load-dictionary.mdx +++ b/docs-templates/api/config/load-dictionary.mdx @@ -7,10 +7,12 @@ description: API reference for the loadDictionary() function `loadDictionary` will load a translation json file for a given locale. -This function is intended for those who which to use `__PACKAGE_NAME__` as a stand-alone i18n library. +This function is intended for those who wish to use `__PACKAGE_NAME__` as a stand-alone i18n library. This function is primarily used to migrate existing projects with i18n to General Translation while keeping their existing translations. +`loadDictionary` only runs for non-default locales. +The default locale's dictionary must be available synchronously: bundle it with your app and pass it via the `dictionary` option. If multiple translations exist, translations from dictionaries loaded by `loadDictionary` will always take precedence over others. `loadDictionary` only supports the use of JSON files with string translations. @@ -53,17 +55,27 @@ export default async function loadDictionary(locale) { } ``` -Then pass it to your `` component: +Then pass it to `initializeGT()` at startup, along with the bundled default-locale dictionary. +It is not a `` prop. -```jsx title="src/App.js" -import { GTProvider } from '__PACKAGE_NAME__'; +```jsx title="src/index.js" +import { initializeGT } from '__PACKAGE_NAME__'; +import dictionary from '../public/locales/en.json'; import loadDictionary from './loadDictionary'; - - - +initializeGT({ + defaultLocale: 'en', + locales: ['en', 'es', 'fr'], + dictionary, // default-locale dictionary, bundled synchronously + loadDictionary, // loads dictionaries for non-default locales +}); ``` + + **Default locale:** `loadDictionary` is never called for the default locale. + Always pass the default-locale dictionary through the `dictionary` option so it is available synchronously. + + **Question:** What's the difference between [`loadTranslations`](__DOCS_PATH__/api/config/load-translations) and [`loadDictionary`](__DOCS_PATH__/api/config/load-dictionary)? @@ -79,6 +91,7 @@ import loadDictionary from './loadDictionary'; ## Notes * `loadDictionary` is used to load custom translations for your app. + * `loadDictionary` only runs for non-default locales. The default locale's dictionary comes from the `dictionary` option and must be available synchronously. * Dictionaries loaded by `loadDictionary` will take precedence over translations loaded by [`loadTranslations`](__DOCS_PATH__/api/config/load-translations). ## Next steps diff --git a/docs-templates/api/config/load-translations.mdx b/docs-templates/api/config/load-translations.mdx index 791a399f..4d4326dd 100644 --- a/docs-templates/api/config/load-translations.mdx +++ b/docs-templates/api/config/load-translations.mdx @@ -43,18 +43,18 @@ A `Promise` that resolves to either a string or JSX object containing the t ## Setup -You must import the `loadTranslations` function and assign it as a prop to the `` component. +Import the `loadTranslations` function and pass it to `initializeGT()` at startup. +It is not a `` prop. ```jsx title="src/index.js" +import { initializeGT } from '__PACKAGE_NAME__'; import loadTranslations from './loadTranslations'; -createRoot(document.getElementById("root")!).render( - - // [!code highlight] - - - -); +initializeGT({ + defaultLocale: 'en', + locales: ['en', 'es', 'fr'], + loadTranslations, // [!code highlight] +}); ``` --- diff --git a/docs-templates/api/dictionary/use-translations.mdx b/docs-templates/api/dictionary/use-translations.mdx index 13275afc..d9160b55 100644 --- a/docs-templates/api/dictionary/use-translations.mdx +++ b/docs-templates/api/dictionary/use-translations.mdx @@ -44,16 +44,27 @@ t('greeting.hello'); // pass the id to get a translation ### Returns -A translation function `d` that, given an id, will return the translated version of the corresponding entry +A translation function `t` that, given an id, returns the translated version of the corresponding entry ```jsx -(id: string, options?: DictionaryTranslationOptions) => React.ReactNode +(id: string, options?: TranslationVariables) => string ``` | Name | Type | Description | |-----------------------|--|-----------------------------------------------------------------------------| | `id` | `string` | The id of the entry to be translated | -| `options?` | [`DictionaryTranslationOptions`](__DOCS_PATH__/api/types/dictionary-translation-options) | Translation options to customize the behavior of `d`. | +| `options?` | [`TranslationVariables`](__DOCS_PATH__/api/types/dictionary-translation-options) | Variables to interpolate into the translated entry. | + +Metadata such as context does not go in the `t()` call. +Instead, it lives in the dictionary entry itself, e.g. `greeting: ['Hello!', { $context: 'a friendly greeting' }]`. + +### Throws + +`t(id)` and `t.obj(id)` throw an `Error` (`Dictionary entry ${id} cannot be found`) when the entry does not exist in the default locale's dictionary. +This applies in both development and production. + +If the source entry exists but the current locale's translation is missing, `t` does not throw. +It falls back to the source entry, translating it at runtime in development when possible. --- @@ -72,26 +83,33 @@ export default dictionary; When we want to access these entries, we call `useTranslations`. This returns a function that accepts the key of a translation from the dictionary. -You must pass the dictionary to the `GTProvider` component. +You must pass the dictionary to `initializeGT()` via the `dictionary` option. + +```jsx title="src/index.js" copy +import { initializeGT } from '__PACKAGE_NAME__'; +import dictionary from './dictionary'; + +initializeGT({ + // ...your config + dictionary, // [!code highlight] +}); +``` ```jsx title="TranslateGreeting.jsx" copy import { useTranslations } from '__PACKAGE_NAME__'; -import dictionary from "./dictionary.json" export default function TranslateGreeting() { const t = useTranslations(); // [!code highlight] return ( - -

- {t('greeting')} // [!code highlight] -

-
+

+ {t('greeting')} // [!code highlight] +

); } ``` ### Using variables [#variables] -In order to pass values, you must (1) assign an identifier and (2) reference the identifier when calling the `d` function. +In order to pass values, you must (1) assign an identifier and (2) reference the identifier when calling the `t` function. In this example, we use `{}` to pass variables to the translations. In the dictionary, we assign identifier `{userName}`. @@ -152,5 +170,8 @@ export default function UserDetails() { ## Notes * The `useTranslations` function allows you to access dictionary translations. * The `useTranslations` hook can only be used within a component wrapped by a [`` component](__DOCS_PATH__/api/components/gtprovider). + * The `t()` function throws when the requested entry is missing from the default locale's dictionary. Make sure every id you reference exists in the source dictionary. + * When only the current locale's translation is missing, `t()` falls back to the source entry instead of throwing. + * Entry metadata (`$context`, `$format`, `$maxChars`) belongs in the dictionary entry, not in the `t()` call. ## Next steps diff --git a/docs-templates/api/strings/msg.mdx b/docs-templates/api/strings/msg.mdx index 487ab940..e71a5d64 100644 --- a/docs-templates/api/strings/msg.mdx +++ b/docs-templates/api/strings/msg.mdx @@ -41,7 +41,7 @@ console.log(decodedString); // "Hello, world!" | Name | Type | Description | |-----------------------|--|-----------------------------------------------------------------------------| | `content` | `string` | The string content to be encoded. | -| `options?` | [`InlineTranslationOptions`](__DOCS_PATH__/api/types/inline-translation-options) | Translation options to customize the behavior of `msg`. | +| `options?` | [`GTTranslationOptions`](__DOCS_PATH__/api/types/inline-translation-options) | Translation options to customize the behavior of `msg`. | ### Returns diff --git a/docs-templates/api/strings/use-gt.mdx b/docs-templates/api/strings/use-gt.mdx index d226df01..280c487f 100644 --- a/docs-templates/api/strings/use-gt.mdx +++ b/docs-templates/api/strings/use-gt.mdx @@ -30,13 +30,13 @@ None A callback function, `gt`, which translates the provided content. ```jsx -(content: string, options?: InlineTranslationOptions) => string +(content: string, options?: GTTranslationOptions) => string ``` | Name | Type | Description | | ---------- | -------------------------------------------------------------------------------- | ----------------------------------------------------- | | `content` | `string` | The string content to be translated. | -| `options?` | [`InlineTranslationOptions`](__DOCS_PATH__/api/types/inline-translation-options) | Translation options to customize the behavior of `gt`. | +| `options?` | [`GTTranslationOptions`](__DOCS_PATH__/api/types/inline-translation-options) | Translation options to customize the behavior of `gt`. | --- @@ -124,21 +124,6 @@ export default function TranslateGreeting() { documentation](https://unicode-org.github.io/icu/userguide/format_parse/messages/).
-### Importing from `__PACKAGE_NAME__` - -If operating under the `"use client"` directive, you should import from `__PACKAGE_NAME__` instead of `__PACKAGE_NAME__`. - -```jsx copy -'use client'; -import { useGT } from '__PACKAGE_NAME__'; - -export default function TranslateGreeting() { - const gt = useGT(); - - return

{gt('Hello, Alice!')}

; -} -``` - --- ## Notes diff --git a/docs-templates/api/strings/use-messages.mdx b/docs-templates/api/strings/use-messages.mdx index dc5ae3a1..777aaa3b 100644 --- a/docs-templates/api/strings/use-messages.mdx +++ b/docs-templates/api/strings/use-messages.mdx @@ -30,13 +30,13 @@ None A callback function, `m`, which translates the provided encoded content from `msg`. ```jsx -(encodedContent: string, options?: Record) => string +(encodedContent: string, options?: GTTranslationOptions) => string ``` | Name | Type | Description | | ---------------- | --------------------- | ------------------------------------------------------------ | | `encodedContent` | `string` | The encoded string content from `msg` to be translated. | -| `options?` | `Record` | Optional parameters to pass variables to the encoded string. | +| `options?` | [`GTTranslationOptions`](__DOCS_PATH__/api/types/inline-translation-options) | Translation options to customize the behavior of `m`. | --- @@ -146,23 +146,6 @@ export default function TranslateGreeting() { documentation](https://unicode-org.github.io/icu/userguide/format_parse/messages/). -### Importing from `__PACKAGE_NAME__` - -If operating under the `"use client"` directive, you should import from `__PACKAGE_NAME__` instead of `__PACKAGE_NAME__`. - -```jsx copy -'use client'; -import { msg, useMessages } from '__PACKAGE_NAME__'; - -const encodedGreeting = msg('Hello, Alice!'); - -export default function TranslateGreeting() { - const m = useMessages(); - - return

{m(encodedGreeting)}

; -} -``` - --- ## Notes diff --git a/docs-templates/api/types/dictionary-translation-options.mdx b/docs-templates/api/types/dictionary-translation-options.mdx index e54cffa4..af5aee9c 100644 --- a/docs-templates/api/types/dictionary-translation-options.mdx +++ b/docs-templates/api/types/dictionary-translation-options.mdx @@ -1,13 +1,18 @@ --- -title: DictionaryTranslationOptions -description: API reference for the DictionaryTranslationOptions type +title: TranslationVariables +description: API reference for the TranslationVariables type --- ## Overview -The `DictionaryTranslationOptions` type is used to pass variables to dictionary entries and specify their render behavior. +The `TranslationVariables` type is used to pass interpolation variables to dictionary entries. It is used with [`useTranslations`](__DOCS_PATH__/api/dictionary/use-translations) to pass variables to dictionary entries. +This page formerly documented the `DictionaryTranslationOptions` type, which no longer exists. + +Entry metadata such as `$context` is not passed to the `t()` call. +Instead, it lives in the dictionary entry itself (typed `DictionaryEntryOptions`), e.g. `greeting: ['Hello!', { $context: 'a friendly greeting' }]`. + **Buildtime Translation:** @@ -25,7 +30,7 @@ It is used with [`useTranslations`](__DOCS_PATH__/api/dictionary/use-translation ', + type: 'Record', optional: true, default: 'undefined', }, @@ -38,6 +43,24 @@ It is used with [`useTranslations`](__DOCS_PATH__/api/dictionary/use-translation | ---- | ----------- | | `variables` | An object where the keys identify where each value is mapped to in the dictionary entry.| +### Entry metadata + +Metadata for a dictionary entry is defined on the entry itself with the `DictionaryEntryOptions` type, not passed to `t()`. + +| Field | Description | +| ----- | ----------- | +| `$context` | Additional context for the entry, used to refine the translation. | +| `$format` | The data format for the entry (e.g. `'ICU'`). Defaults to `'ICU'`. | +| `$maxChars` | Limits the character count of the translation. | + +```jsx title="dictionary.ts" +const dictionary = { + greeting: ['Hello!', { $context: 'a friendly greeting' }], +}; + +export default dictionary; +``` + --- @@ -45,7 +68,7 @@ It is used with [`useTranslations`](__DOCS_PATH__/api/dictionary/use-translation ### Passing variables -In order to pass a variable to the dictionary entry, we need to do two things: (1) add a variable to the entry and (2) reference said variable in the [`d`](__DOCS_PATH__/api/dictionary/use-translations) invocation. +In order to pass a variable to the dictionary entry, we need to do two things: (1) add a variable to the entry and (2) reference said variable in the [`t`](__DOCS_PATH__/api/dictionary/use-translations) invocation. First, we add a variable to the dictionary entry with the following syntax: `{username}`. `username` is the name of the variable. @@ -109,8 +132,9 @@ const Component = () => { --- ## Notes + * `TranslationVariables` was formerly named `DictionaryTranslationOptions`. * The `variables` object passes values to a dictionary entry. - * The `variablesOptions` object defines the behavior of the variables. + * Entry metadata (`$context`, `$format`, `$maxChars`) belongs in the dictionary entry itself, typed as `DictionaryEntryOptions`. ## Next steps * See [dictionaries](__DOCS_PATH__/guides/dictionaries) for more information on dictionaries and common practices. diff --git a/docs-templates/api/types/inline-translation-options.mdx b/docs-templates/api/types/inline-translation-options.mdx index 74e1b1ed..7b8882a5 100644 --- a/docs-templates/api/types/inline-translation-options.mdx +++ b/docs-templates/api/types/inline-translation-options.mdx @@ -1,14 +1,18 @@ --- -title: InlineTranslationOptions -description: API reference for the InlineTranslationOptions type +title: GTTranslationOptions +description: API reference for the GTTranslationOptions type --- ## Overview -The `InlineTranslationOptions` type is used to pass variables to inline translations and specify their render behavior. +The `GTTranslationOptions` type is used to pass variables to inline translations and provide metadata for the translation. You can also add context and an identifier to the translation. It is used with [`useGT`](__DOCS_PATH__/api/strings/use-gt) and [`msg`](__DOCS_PATH__/api/strings/msg) to pass variables to inline string translations. +This type was formerly named `InlineTranslationOptions`. + +`GTTranslationOptions` combines interpolation variables (`TranslationVariables`) with `$`-prefixed metadata fields. + **Buildtime Translation:** `useGT` and `msg` translations occur at buildtime; however, variables are never translated. @@ -23,7 +27,37 @@ It is used with [`useGT`](__DOCS_PATH__/api/strings/use-gt) and [`msg`](__DOCS_P ', + type: 'Record', + optional: true, + default: 'undefined', + }, + "$context?": { + type: 'string', + optional: true, + default: 'undefined', + }, + "$id?": { + type: 'string', + optional: true, + default: 'undefined', + }, + "$format?": { + type: 'string', + optional: true, + default: "'ICU'", + }, + "$locale?": { + type: 'string', + optional: true, + default: 'undefined', + }, + "$maxChars?": { + type: 'number', + optional: true, + default: 'undefined', + }, + "$requiresReview?": { + type: 'boolean', optional: true, default: 'undefined', }, @@ -35,10 +69,12 @@ It is used with [`useGT`](__DOCS_PATH__/api/strings/use-gt) and [`msg`](__DOCS_P | Prop | Description | | ---- | ----------- | | `variables` | An object where the keys identify where each value is mapped to in the string.| -| `$context` | Optionally include `$context` as a variable in the `variables` object to provide context for the content (used for translation). | -| `$id` | Optionally include `$id` as a variable in the `variables` object to provide an identifier for use with the translation editor. | -| `$maxChars` | Optionally include `$maxChars` as a variable to limit the character count of the translation. The library strictly enforces this limit using `formatCutoff()` logic. | -| `$requiresReview` | Optionally include `$requiresReview` as a variable to gate the translation behind a human-review step before it is served. Must be a boolean literal. | +| `$context` | Additional context for the content, used to refine the translation. | +| `$id` | An identifier for the message, used as descriptive metadata on the GT platform. | +| `$format` | The data format for the message (e.g. `'ICU'`). Defaults to `'ICU'`. | +| `$locale` | The locale to use for the translation. Defaults to the current locale. | +| `$maxChars` | Limits the character count of the translation. The library strictly enforces this limit using `formatCutoff()` logic. | +| `$requiresReview` | Gates the translation behind a human-review step before it is served. Must be a boolean literal. | --- @@ -127,9 +163,10 @@ const Component = () => { --- ## Notes - * `InlineTranslationOptions` is used for inline string translations. - * The `variables` object passes values to the text. - * The `variablesOptions` object defines the behavior of the variables. + * `GTTranslationOptions` is used for inline string translations. + * `GTTranslationOptions` was formerly named `InlineTranslationOptions`. + * Keys without a `$` prefix are interpolation variables that pass values to the text. + * Keys with a `$` prefix are metadata for the translation. ## Next steps diff --git a/docs-templates/concepts/environments.mdx b/docs-templates/concepts/environments.mdx index f9c8bcbd..f43aa32e 100644 --- a/docs-templates/concepts/environments.mdx +++ b/docs-templates/concepts/environments.mdx @@ -14,15 +14,17 @@ It detects the environment by checking the `NODE_ENV` environment variable. ### Environment variables -In production, the only accepted environment variable is `GT_PROJECT_ID` (or a prefixed version thereof, such as `NEXT_PUBLIC_GT_PROJECT_ID`). +`__PACKAGE_NAME__` reads credentials from environment variables only — API keys and project IDs cannot be passed as configuration options in code. -If an API key is provided as an environment variable, `__PACKAGE_NAME__` will throw an error. This is to prevent API keys from being exposed to the client. +In production, `__PACKAGE_NAME__` uses your project ID to load translations from the General Translation CDN. Set it with the `GT_PROJECT_ID` environment variable in server environments. Client-side code only receives the project ID through your framework's public prefix (such as `NEXT_PUBLIC_GT_PROJECT_ID` or `VITE_GT_PROJECT_ID`) — a bare `GT_PROJECT_ID` is never exposed to the client bundle. + +Server environments also read a production API key from `GT_API_KEY`. Never expose an API key to client-side code. ### Translation loading behavior -In production, the `__PACKAGE_NAME__` provider will attempt to load translations from the General Translation CDN, by default. +In production, `__PACKAGE_NAME__` will attempt to load translations from the General Translation CDN, by default. -If you have configured custom translation loading behavior, such as local translations, via the `loadTranslations` function `__PACKAGE_NAME__` will use that instead. +If you have configured custom translation loading behavior, such as local translations, via the `loadTranslations` function, `__PACKAGE_NAME__` will use that instead. Translation hot reloading is disabled since it is in production. @@ -30,15 +32,17 @@ Translation hot reloading is disabled since it is in production. ### Environment variables -Since development is local and not exposed to foreign users, `__PACKAGE_NAME__` will accept any General Translation environment variables, even if they are prefixed with `NEXT_PUBLIC_`, `VITE_`, (or similar). +In development, `__PACKAGE_NAME__` also reads a development API key from the environment to enable translation hot reloading and on-demand translation. Set `GT_DEV_API_KEY` in server environments, or the prefixed version your framework exposes to client-side code (such as `NEXT_PUBLIC_GT_DEV_API_KEY` or `VITE_GT_DEV_API_KEY`). + +Development API keys are intended for local development only — never set one in a production environment. ### Translation loading behavior -In development, the `__PACKAGE_NAME__` provider will first attempt to load translations in the same way as production. +In development, `__PACKAGE_NAME__` will first attempt to load translations in the same way as production. These translations are loaded into memory. -When rendering a component (that uses `useGT`, ``, or `useTranslations`) in a language different than the default, the `__PACKAGE_NAME__` provider will do the following: +When rendering a component (that uses `useGT`, ``, or `useTranslations`) in a language different than the default, `__PACKAGE_NAME__` will do the following: 1. If it detects a valid, stored translation for the given content, it will render the translation. 2. If no translation is found, it will attempt to dynamically translate the content via the General Translation API. diff --git a/docs-templates/guides/dictionaries.mdx b/docs-templates/guides/dictionaries.mdx index 22f92cb8..199d0221 100644 --- a/docs-templates/guides/dictionaries.mdx +++ b/docs-templates/guides/dictionaries.mdx @@ -85,20 +85,18 @@ Or use JSON format: } ``` -Then you pass it to your [``](__DOCS_PATH__/api/components/gtprovider) component: +Then register it with `initializeGT()` at your app's entry point, before rendering: ```jsx title="index.js" copy +import { initializeGT } from "__PACKAGE_NAME__"; import dictionary from "./dictionary.js"; import config from "./gt.config.json"; -createRoot(document.getElementById("root")!).render( - - {/* [!code highlight] */} - - - - -); +initializeGT({ + defaultLocale: config.defaultLocale, + locales: config.locales, + dictionary, // [!code highlight] +}); ``` ### Step 2: Use in components @@ -223,23 +221,20 @@ export default async function loadTranslations(locale: string) { } ``` -Pass it to your ``: +Register it with `initializeGT()`: ```tsx title="src/index.tsx" +import { initializeGT } from '__PACKAGE_NAME__'; import loadTranslations from './loadTranslations'; import dictionary from './dictionary'; - -createRoot(document.getElementById("root")!).render( - - - - - -); +import config from './gt.config.json'; + +initializeGT({ + defaultLocale: config.defaultLocale, + locales: config.locales, + dictionary, + loadTranslations, +}); ``` GT automatically generates translations for other languages based on your base dictionary. Run `npx gt translate` to generate translations for all configured languages. @@ -254,6 +249,25 @@ export default async function loadDictionary(locale: string) { } ``` +Register it with `initializeGT()` alongside your default-locale dictionary: + +```tsx title="src/index.tsx" +import { initializeGT } from '__PACKAGE_NAME__'; +import loadDictionary from './loadDictionary'; +import dictionary from './dictionary'; + +initializeGT({ + defaultLocale: 'en', + locales: ['es', 'fr', 'de'], + dictionary, + loadDictionary, +}); +``` + + + **Note:** `loadDictionary` only runs for non-default locales. The default-locale dictionary must be bundled with your app and passed synchronously via the `dictionary` option. + + This loads JSON translation files from your `public/locales/` directory: diff --git a/docs-templates/guides/local-tx.mdx b/docs-templates/guides/local-tx.mdx index 2dc6e405..10f36dca 100644 --- a/docs-templates/guides/local-tx.mdx +++ b/docs-templates/guides/local-tx.mdx @@ -42,20 +42,17 @@ export default async function loadTranslations(locale: string) { } ``` -### Step 2: Configure GTProvider -Pass `loadTranslations` as a prop to the [``](__DOCS_PATH__/api/components/gtprovider) component: +### Step 2: Configure loadTranslations +Register `loadTranslations` with `initializeGT()` at your app's entry point, before rendering: -```tsx title="src/App.tsx" -import { GTProvider } from '__PACKAGE_NAME__'; +```tsx title="src/index.tsx" +import { initializeGT } from '__PACKAGE_NAME__'; import loadTranslations from './loadTranslations'; -export default function App() { - return ( - - - - ); -} +initializeGT({ + locales: ['es', 'fr'], + loadTranslations, +}); ``` ### Step 3: Configure CLI diff --git a/docs-templates/guides/migration.mdx b/docs-templates/guides/migration.mdx index af3dfffa..1f3179f9 100644 --- a/docs-templates/guides/migration.mdx +++ b/docs-templates/guides/migration.mdx @@ -71,15 +71,16 @@ You'll never have to wait for translations again. } ``` - Add the `` component to the root of your app, and spread the `config` object as props. + Call `initializeGT()` with your configuration at your app's entry point, then add the `` component to the root of your app. ```tsx - import { GTProvider } from '__PACKAGE_NAME__' + import { initializeGT } from '__PACKAGE_NAME__' import config from './gt.config.json' - - - + initializeGT({ + defaultLocale: config.defaultLocale, + locales: config.locales, + }) ``` For more detailed steps, see the [project quickstart](__DOCS_PATH__) guide. @@ -127,8 +128,8 @@ You'll need to replace it with: ```tsx export default function MyComponent() { - const { t } = useGT() - return
{t('Hello, world!')}
+ const gt = useGT() + return
{gt('Hello, world!')}
} // OR export default function MyComponent() { @@ -171,16 +172,18 @@ The `useTranslations` hook behaves very similarly to `useTranslation` hooks, and In terms of configuration, you'll need to create a `dictionary.[js|ts|json]` file in your project root or `src` directory. -Copy the contents of your old dictionary file into this new file, then pass it to the `GTProvider` component. +Copy the contents of your old dictionary file into this new file, then register it with `initializeGT()` at your app's entry point. ```tsx -import { GTProvider } from '__PACKAGE_NAME__' +import { initializeGT } from '__PACKAGE_NAME__' import dictionary from './dictionary.json' import config from './gt.config.json' - - - +initializeGT({ + defaultLocale: config.defaultLocale, + locales: config.locales, + dictionary, +}) ``` See the [dictionaries](__DOCS_PATH__/guides/dictionaries) guide for more details. diff --git a/docs-templates/guides/strings.mdx b/docs-templates/guides/strings.mdx index 18f054cb..aa60d331 100644 --- a/docs-templates/guides/strings.mdx +++ b/docs-templates/guides/strings.mdx @@ -104,7 +104,7 @@ For advanced formatting, use ICU syntax: ```jsx const gt = useGT(); -translate('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count: 10 }); +gt('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count: 10 }); ``` diff --git a/docs-templates/reference/gt-jsx.mdx b/docs-templates/reference/gt-jsx.mdx index f0c1cd58..e6856087 100644 --- a/docs-templates/reference/gt-jsx.mdx +++ b/docs-templates/reference/gt-jsx.mdx @@ -251,7 +251,7 @@ type GTJSXFile = { } ``` -Where `key` is either user-defined or the hash of the original language `GTJSXTree`, +Where `key` is the hash of the original language `GTJSXTree`, and `GTJSXTree` is the type of the GT JSX tree described above. ### Complete example @@ -334,9 +334,10 @@ Which can then be displayed as the intended UI: Hashing algorithm, hash length TBD -### Avoiding hashes at runtime +### The `id` prop -To avoid computing hashes at runtime, the libraries have an optional fallback mechanism where the user can specify an ID. +The `id` prop does not change the key used to look up a translation. +Keys are always hashes computed from the message content plus its `context` and `maxChars` metadata (and review metadata). ```jsx @@ -344,10 +345,6 @@ To avoid computing hashes at runtime, the libraries have an optional fallback me ``` -If the ID is present in the translation JSON file, it will be used instead of the hash. - -```json -{ "example": "Hello, world" } -``` +Here, `example` is descriptive metadata sent to the GT platform; the translation is still stored and looked up under the content hash. diff --git a/docs/en-US/cli/features/auto-jsx-injection.mdx b/docs/en-US/cli/features/auto-jsx-injection.mdx index e74e8914..570eab40 100644 --- a/docs/en-US/cli/features/auto-jsx-injection.mdx +++ b/docs/en-US/cli/features/auto-jsx-injection.mdx @@ -27,6 +27,8 @@ Auto JSX injection is **disabled by default**. } ``` +If your app uses an older `gt-react` major, also set [`legacyGtReactImportSource`](/docs/cli/reference/config#parsingflags) to `true` in `parsingFlags` so the compiler emits its injected imports from `gt-react/browser` instead of `gt-react`. + ## Example Without auto JSX injection: diff --git a/docs/en-US/cli/reference/config.mdx b/docs/en-US/cli/reference/config.mdx index 39fb8931..7897f29c 100644 --- a/docs/en-US/cli/reference/config.mdx +++ b/docs/en-US/cli/reference/config.mdx @@ -163,6 +163,7 @@ Each file type should correspond to an object that contains one or more of the f - `transform` - `transformationFormat` - `requiresReview` +- `parsingFlags` - `output` ### `include` @@ -311,6 +312,34 @@ You can also set a top-level `requiresReview` boolean in your configuration to a **Note:** File-type `requiresReview` config sets the review policy for matched files without changing individual content hashes. To gate a single component or string, use the `requiresReview` / `$requiresReview` prop instead. +### `parsingFlags` [#parsingflags] + +The `parsingFlags` key controls how the CLI and compiler parse your source files. It is only supported for the `gt` file type. + +| Parameter | Description | Type | Optional | Default | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | -------- | ------- | +| `autoderive` | Parse interpolated values as [`derive()`](/docs/next/api/strings/derive) calls. A boolean enables both strings and JSX; an object enables them selectively. See [autoderive](/docs/cli/features/autoderive). | `boolean \| object` | `true` | `false` | +| `enableAutoJsxInjection` | Automatically wrap translatable JSX text in translation components at build time. See [auto JSX injection](/docs/cli/features/auto-jsx-injection). | `boolean` | `true` | `false` | +| `legacyGtReactImportSource` | Emit compiler-injected imports from `gt-react/browser` instead of `gt-react`, for compatibility with older `gt-react` majors. | `boolean` | `true` | `false` | + +```json +{ + "files": { + "gt": { + "output": "public/i18n/[locale].json", + "parsingFlags": { + "autoderive": true, + "legacyGtReactImportSource": true + } + } + } +} +``` + + +**Note:** `legacyGtReactImportSource` is also available as a compiler plugin option. When both are set, the plugin option takes precedence over the `gt.config.json` value. + + ### `output` This key is exclusively used for General Translation files, specifically for saving translations locally. If you are using the GT CDN, this key is not needed. @@ -340,6 +369,7 @@ Currently, only one file for each locale can be generated. **Supported Keys** - `output` (Required) +- `parsingFlags` (Optional) **Example** diff --git a/docs/en-US/core/class/constructor.mdx b/docs/en-US/core/class/constructor.mdx index 6dd23740..fdefd408 100644 --- a/docs/en-US/core/class/constructor.mdx +++ b/docs/en-US/core/class/constructor.mdx @@ -114,6 +114,7 @@ const gt = new GT({ - All parameters are optional, but API operations will require `apiKey` and `projectId` - The constructor validates all locale codes immediately, throwing errors for invalid codes - Custom mappings take precedence over standard BCP 47 validation +- `GT` extends the `GTRuntime` class from `generaltranslation/runtime`, which accepts the same constructor parameters but omits the project and file-management methods ## Next steps diff --git a/docs/en-US/core/index.mdx b/docs/en-US/core/index.mdx index 4d76d69f..d6530e6b 100644 --- a/docs/en-US/core/index.mdx +++ b/docs/en-US/core/index.mdx @@ -127,6 +127,27 @@ await gt.uploadSourceFiles(files); --- +## The `GTRuntime` class + +The `GT` class extends `GTRuntime`, a leaner base class available from the `generaltranslation/runtime` entrypoint. +`GTRuntime` provides translation (`translate`, `translateMany`), formatting, and locale utilities — everything except the project and file-management API client — so runtime bundles stay small. + +```typescript +import { GTRuntime } from 'generaltranslation/runtime'; + +const gt = new GTRuntime({ + sourceLocale: 'en', + targetLocale: 'es', +}); + +const price = gt.formatNum(29.99, { style: 'currency', currency: 'USD' }); +const isValid = gt.isValidLocale('de'); +``` + +The `generaltranslation/runtime` entrypoint also exports the [`GTConstructorParams`](/docs/core/types/gt-constructor-params) type, which both classes share. + +--- + ## Table of contents ### GT class diff --git a/docs/en-US/next/api/components/gtprovider.mdx b/docs/en-US/next/api/components/gtprovider.mdx index a5b80c0f..0181949e 100644 --- a/docs/en-US/next/api/components/gtprovider.mdx +++ b/docs/en-US/next/api/components/gtprovider.mdx @@ -8,10 +8,11 @@ description: API reference for the GTProvider component The `` component provides General Translation (GT) context to its children, enabling them to access translated content. It is required for any client-side translations on your application. +`` resolves the request's locale and region on the server and automatically passes translation and dictionary snapshots to the client. You do not need to pass it any configuration. + ### When to use - Wrap your entire application in `` to enable translations on the client. -- When working with dictionaries, optionally specify an `id` to limit the dictionary data sent to the client, optimizing performance for large dictionaries. - The `` component is used for both [inline ``](/docs/next/guides/t) and [dictionaries](/docs/next/guides/dictionaries). ## Reference @@ -20,24 +21,9 @@ It is required for any client-side translations on your application. @@ -46,10 +32,7 @@ It is required for any client-side translations on your application. | Prop | Description | |-----------|-------------| -| `children` | Any component or the parents of any component that needs to translate or access translation information on the client side. These should include any components using ``, `useGT`, or other translation utilities. | -| `id?` | The ID of a nested dictionary to limit the data sent to the client. This is useful for large projects with extensive dictionaries. | -| `locale?` | An optional locale override. If provided, this locale will be used instead of the automatically detected one. | -| `region?` | An optional region override for locale-specific formatting. | +| `children?` | Any component or the parents of any component that needs to translate or access translation information on the client side. These should include any components using ``, `useGT`, or other translation utilities. | ### Returns @@ -77,30 +60,11 @@ export default function RootLayout({ children }) { } ``` -### Using the id prop for subsets - -Specify the `id` prop to optimize performance by sending only a subset of the dictionary to the client. - -```jsx title="layout.js" copy -import { GTProvider } from 'gt-next'; - -export default function RootLayout({ children }) { - return ( - - - // [!code highlight] - {children} - - - - ); -} -``` - --- ## Notes * The `` must wrap all `` components and other translation-related components in client components. Read more about it [here](/docs/next/guides/t). + * `` resolves the request locale and region itself. To change how the locale is determined, configure [`withGTConfig`](/docs/next/api/config/with-gt-config). * For server-side translations, `` is not required but can still be used. ## Next steps diff --git a/docs/en-US/next/api/components/link.mdx b/docs/en-US/next/api/components/link.mdx new file mode 100644 index 00000000..7a0b7448 --- /dev/null +++ b/docs/en-US/next/api/components/link.mdx @@ -0,0 +1,96 @@ +--- +title: Link +description: API reference for the Link component +--- + +## Overview + +The `` component is a locale-aware wrapper around [`next/link`](https://nextjs.org/docs/app/api-reference/components/link). +It prefixes internal hrefs with the current locale, so `/about` becomes `/fr/about` when the user's locale is `fr`. + +It is a default export, so it drops in as a replacement for `next/link`: + +```tsx +import Link from 'gt-next/link'; +``` + +--- + +## Reference + +### Props + + + +### Description + +| Prop | Description | +|-----------|-------------| +| `href` | The destination URL or URL object. Internal paths are prefixed with the locale. | +| `locale?` | A locale string prefixes the href with that locale. `false` disables prefixing. When omitted, the current locale is used. | + +`` accepts all `next/link` props (`LinkProps = ComponentProps`), including `replace`, `scroll`, and `prefetch`. + +### Returns + +The rendered Next.js link with a localized href. + +--- + +## Examples + +### Basic usage + +```tsx title="src/components/Navigation.tsx" copy +import Link from 'gt-next/link'; + +export function Navigation() { + return Home; // renders /en/home when the locale is en +} +``` + +### Forcing a specific locale + +```tsx title="src/components/LocaleSwitcher.tsx" copy +import Link from 'gt-next/link'; + +export function LocaleSwitcher() { + return French; // renders /fr/home +} +``` + +### Disabling prefixing + +```tsx title="src/components/UnlocalizedLink.tsx" copy +import Link from 'gt-next/link'; + +export function UnlocalizedLink() { + return Legal; // renders /legal +} +``` + +--- + +## Notes + +* Only internal paths that start with a single `/` are prefixed. External URLs (e.g., `https://example.com`) and protocol-relative URLs (starting with `//`) are never prefixed. +* Query strings and hashes in the href are preserved. +* For URL objects, the `pathname` field is prefixed; objects without a string `pathname` are left unchanged. + +--- + +## Next steps + +- [Middleware guide](/docs/next/guides/middleware) - Set up URL-based locale routing +- [`useLocale`](/docs/next/api/helpers/use-locale) - Read the current locale diff --git a/docs/en-US/next/api/components/meta.json b/docs/en-US/next/api/components/meta.json index b95f58ee..3c02cac2 100644 --- a/docs/en-US/next/api/components/meta.json +++ b/docs/en-US/next/api/components/meta.json @@ -3,6 +3,7 @@ "pages": [ "./t", "./gtprovider", + "./link", "./var", "./num", "./currency", diff --git a/docs/en-US/next/api/components/t.mdx b/docs/en-US/next/api/components/t.mdx index 16b13610..702edf06 100644 --- a/docs/en-US/next/api/components/t.mdx +++ b/docs/en-US/next/api/components/t.mdx @@ -61,14 +61,14 @@ Make sure to follow the [deployment guide here](/docs/next/tutorials/quickdeploy | Prop | Description | |-----------------|-------------------------------------------------------------------------------------------------| | `children` | The content to be translated. This can include plain text or JSX structures. | -| `id` | An optional unique identifier for the translation string. If not provided, one is auto-generated at build time. | +| `id` | An optional identifier for the translation, sent to the GT platform as descriptive metadata. It does not affect how translations are looked up. | | `context` | Additional context to refine the translation. Useful for resolving ambiguous phrases. | | `requiresReview` | When `true`, the translation is withheld from serving until it is approved in a human-review step. Must be a boolean literal. `$requiresReview` is an equivalent alias. | ### Returns -`React.JSX.Element|undefined` which contains the rendered translation or fallback content based on the provided configuration. +`React.JSX.Element|undefined` which contains the rendered translation, or the source content when no translation is available. --- @@ -85,13 +85,13 @@ If a translation is not found, it will fallback to the original content. Make sure to follow the [deployment guide here](/docs/next/tutorials/quickdeploy). ### Development -During development, the `` function will translate content on demand. +During development, the `` component will translate content on demand. This is useful for prototyping what your app will look like in different languages. Remember to add a Dev API key to your environment to enable this behavior. - -While loading, `` will return undefined unless languages are similar (en-US vs en-GB), though this behavior can be customized with render settings. -If an error occurs, `` will return the original content. +`` renders synchronously from the loaded translation snapshot. +While an updated translation is loading during hot reload, `` keeps showing the previous output. +If no translation is available, `` renders the original content. You will see a delay during on-demand translation in development. This delay will not occur in production builds unless content is explicitly being translated on demand, @@ -226,6 +226,7 @@ export default function Example() { * The `` component is designed for translating content in your application. It is the primary method for localization in `gt-next`. * Use the `` component to translate plain text or JSX structures, including variables and pluralization. * If you use the `` component on the client side, make sure it is wrapped in a [``](/docs/next/api/components/gtprovider) to access the translation context. + * Translations are looked up by a hash computed from the message content plus `context` and `maxChars` (and review metadata). The `id` prop does not change this hash; it is descriptive metadata sent to the GT platform. * The `requiresReview` prop only accepts a boolean literal. Only the value `true` changes the content hash and withholds the translation until it is approved. ## Next steps diff --git a/docs/en-US/next/api/components/tx.mdx b/docs/en-US/next/api/components/tx.mdx index 9e8c23ad..f12107d3 100644 --- a/docs/en-US/next/api/components/tx.mdx +++ b/docs/en-US/next/api/components/tx.mdx @@ -108,7 +108,8 @@ You can use the `` component to mark children as variables. This allows you to mark content that should not be translated. ```jsx title="DynamicGreeting.jsx" copy -import { Tx, Var } from 'gt-next/server'; +import { Tx } from 'gt-next/server'; +import { Var } from 'gt-next'; export default function DynamicGreeting(user) { return ( @@ -124,7 +125,8 @@ export default function DynamicGreeting(user) { The `` component also supports pluralization using the `` component. ```jsx title="ItemCount.jsx" copy -import { Tx, Plural } from 'gt-next/server'; +import { Tx } from 'gt-next/server'; +import { Plural } from 'gt-next'; export default function ItemCount({ count }) { return ( diff --git a/docs/en-US/next/api/config/load-dictionary.mdx b/docs/en-US/next/api/config/load-dictionary.mdx index c1944386..e086e6fd 100644 --- a/docs/en-US/next/api/config/load-dictionary.mdx +++ b/docs/en-US/next/api/config/load-dictionary.mdx @@ -12,6 +12,9 @@ This function is intended for those who wish to use `gt-next` as a stand-alone i This function is primarily used to migrate existing projects with i18n to General Translation while keeping their existing translations. Follow [this guide](/docs/next/guides/migration) to set this up. +`loadDictionary` only runs for non-default locales. +The default locale's dictionary must be available synchronously: `gt-next` bundles it from your `dictionary.js`, `dictionary.ts`, or `dictionary.json` file. + If multiple translations exist, translations from dictionaries loaded by `loadDictionary` will always take precedence over others. `loadDictionary` only supports the use of JSON files with string translations. @@ -53,6 +56,12 @@ export default async function loadDictionary(locale) { } ``` +If you want to use a different name or path, pass the relative path through the `loadDictionaryPath` parameter in [`withGTConfig`](/docs/next/api/config/with-gt-config). + + + **Default locale:** `loadDictionary` is never called for the default locale. + Keep the default locale's dictionary in your `dictionary.{js,ts,json}` file so it is bundled with your app and available synchronously. + **Question:** What's the difference between [`loadTranslations`](/docs/next/api/config/load-translations) and [`loadDictionary`](/docs/next/api/config/load-dictionary)? @@ -68,6 +77,7 @@ export default async function loadDictionary(locale) { ## Notes * `loadDictionary` is used to load custom translations for your app. + * `loadDictionary` only runs for non-default locales. The default locale's dictionary comes from your `dictionary` file and is bundled with your app. * Dictionaries loaded by `loadDictionary` will take precedence over translations loaded by [`loadTranslations`](/docs/next/api/config/load-translations). ## Next steps diff --git a/docs/en-US/next/api/config/load-translations.mdx b/docs/en-US/next/api/config/load-translations.mdx index 126de486..8ef83d94 100644 --- a/docs/en-US/next/api/config/load-translations.mdx +++ b/docs/en-US/next/api/config/load-translations.mdx @@ -39,7 +39,7 @@ If you are looking to manually define your own translations, check out the [cust ### Returns -A `Promise` that resolves to dictionary mapping ids to translations for the given locale. +A `Promise` that resolves to either a string or JSX object containing the translations for the given locale. --- @@ -57,6 +57,12 @@ export default async function loadTranslations(locale) { If you want to use a different name or path, pass the relative path through the `loadTranslationsPath` parameter in [`withGTConfig`](/docs/next/api/config/with-gt-config). + + **Cache Components:** If `cacheComponents` is enabled in your Next.js config, a custom `loadTranslations` is required. + `gt-next` cannot safely use the default remote translation loader with Cache Components, and the build fails without one. + See the [Cache Components guide](/docs/next/guides/cache-components). + + --- @@ -130,6 +136,7 @@ export default async function loadTranslations(locale) { ## Notes * `loadTranslations` gives you the ability to customize how translations are loaded in your app in production. * Its most common use case is for adding [local translations](/docs/next/guides/local-tx) + * A custom `loadTranslations` is required when `cacheComponents` is enabled in your Next.js config. ## Next steps * Learn about why you might want to use [local translations](/docs/next/guides/local-tx) diff --git a/docs/en-US/next/api/config/with-gt-config.mdx b/docs/en-US/next/api/config/with-gt-config.mdx index e04c0465..228e0f21 100644 --- a/docs/en-US/next/api/config/with-gt-config.mdx +++ b/docs/en-US/next/api/config/with-gt-config.mdx @@ -21,7 +21,7 @@ export default withGTConfig(nextConfig, { ``` -**Legacy** +**Legacy:** `initGT` is the legacy way to configure the `gt-next` library. It returns a function callback which is then called on the `NextConfig` object. The props for both functions are the same, with the exception that `withGTProps` requires `NextConfig` to also be passed in. @@ -29,27 +29,31 @@ The props for both functions are the same, with the exception that `withGTProps` Use `withGTConfig` to: * Configure supported languages and default locale (a.k.a fallback language). - * Set API keys and project IDs for accessing GT services. - * Set loading behavior. * Configure timeout settings. * Set up custom endpoints. * Customize translation behavior, caching, and request batching. - * Configure build-time validation through the SWC plugin. + * Configure build-time validation. - `withGTConfig` must be used in your `next.config.js` file to enable translation functionality. + **Note:** `withGTConfig` must be used in your `next.config.js` file to enable translation functionality. + + + + **Credentials:** API keys and project IDs are read from environment variables, not props. + Set `GT_PROJECT_ID` (or `NEXT_PUBLIC_GT_PROJECT_ID` to expose it to the client) and `GT_API_KEY` for production, + and `GT_DEV_API_KEY` (or `NEXT_PUBLIC_GT_DEV_API_KEY`) for development. ## Reference -By default, `withGTConfig` will look for a `gt.config.json` file in the same directory as your `next.config.js` file. +By default, `withGTConfig` will look for a `gt.config.json` file in the same directory as your `next.config.js` file, then fall back to `./.gt/gt.config.json`. This json file will be loaded and merged with the configuration passed to `withGTConfig`. See the [gt.config.json](/docs/next/api/config/gt-config-json) reference for more information on the configuration file. - The CLI tool will only read the configuration from the `gt.config.json` file, so + **Recommendation:** The CLI tool will only read the configuration from the `gt.config.json` file, so we recommend using the `gt.config.json` file as a source of truth for your app. Additional configuration options not in the `gt.config.json` file can be passed to `withGTConfig` directly as props. @@ -96,22 +100,6 @@ See the [gt.config.json](/docs/next/api/config/gt-config-json) reference for mor ### Advanced props | Prop | Description | |--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `projectId` | Project ID, which can be included here or as an environment variable. | -| `apiKey` | Though not recommended, an API key, which can be included here. It can also be included as an environment variable. | -| `devApiKey` | Though not recommended, a development API key, which can be included here. It can also be included as an environment variable. | -| `preferredModelProvider` | Your first choice AI model provider. Currently only [Anthropic](https://anthropic.com) or [OpenAI](https://openai.com) are enabled. Leave this blank and we'll figure out the best provider on a translation-by-translation basis. In periods of high usage or when a provider is disabled, we can't guarantee that your preferred provider will be used. | | `runtimeUrl` | Base URL for the GT API. To disable automatic translation, set this to an empty string. | | `cacheUrl` | URL where cached translations are stored. Can be customized to point to a custom cache server. | | `cacheExpiryTime` | Time in milliseconds before locally cached translations expire. | -| `renderSettings` | An object specifying loading behavior for runtime translations. | +| `renderSettings` | An object specifying the runtime translation timeout. See [render settings](#render-settings). | | `maxConcurrentRequests` | Maximum number of concurrent translation requests allowed to the GT API. | | `maxBatchSize` | Maximum number of translations to batch together before sending a request. | | `batchInterval` | Interval in milliseconds between batched translation requests. Helps control the rate at which requests are sent. | -| `dictionary` | Optional configuration filepath for the dictionary. Similar to `i18n`, it accepts a string to specify a custom path. Dictionaries called `dictionary.js` (or `.jsx`, `.ts`, `.tsx` etc.) and placed at the root or in the `src` folder are supported by default. | +| `dictionary` | Optional filepath for the dictionary. See [dictionary detection](#dictionary-detection). | +| `loadTranslationsPath` | Optional filepath for a custom [`loadTranslations`](/docs/next/api/config/load-translations) function. | +| `loadDictionaryPath` | Optional filepath for a custom [`loadDictionary`](/docs/next/api/config/load-dictionary) function. | +| `getLocalePath` | Optional filepath for a custom `getLocale` request function that determines the locale for each request. | +| `getRegionPath` | Optional filepath for a custom `getRegion` request function that determines the region for each request. | +| `headersAndCookies` | Custom names for the headers and cookies `gt-next` uses. See [headers and cookies](#headers-and-cookies). | @@ -174,29 +182,22 @@ See the [gt.config.json](/docs/next/api/config/gt-config-json) reference for mor ### Returns A `NextConfig` object enhanced with the specified GT settings. - + ### Exceptions -Throws an `Error` if the `projectId` is missing and default URLs are used, or if the API key is required and missing. +Throws an `Error` if `GT_PROJECT_ID` is missing and default URLs are used, or if an API key is required and missing. --- -## Render settings +## Render settings [#render-settings] -Render settings controls the behavior of translations while they are loading. -This only applies to translations that are happening at runtime. -If the translation is cached, response time is too low to justify loading behavior. +Render settings control the timeout for runtime translations. +This only applies to translations that happen at runtime; cached translations are not affected. | Prop | Description | |-----------|-----------------------------------------------------------------------------| -| `method` | The method used to render the page. Options are `skeleton`, `replace`, and `default`. | -| `timeout` | The time in milliseconds before the method times out. Default is 8000 ms. | +| `timeout` | The time in milliseconds before a runtime translation times out. Defaults to 8000 ms in development and 12000 ms in production. | + +When a runtime translation exceeds the timeout, `gt-next` renders the content in the default language instead. + +--- + +## Headers and cookies [#headers-and-cookies] + +Use the `headersAndCookies` prop to rename the header and cookies `gt-next` uses to track locale state. +You only need this if the default names conflict with your own. + +| Field | Description | Default | +|-------|-------------|---------| +| `localeHeaderName` | Header that carries the request locale | `x-generaltranslation-locale` | +| `localeCookieName` | Cookie that stores the user's selected locale | `generaltranslation.locale` | +| `enableI18nCookieName` | Cookie that toggles i18n for the request | `generaltranslation.enable-i18n` | +| `referrerLocaleCookieName` | Cookie that tracks the referrer locale | `generaltranslation.referrer-locale` | +| `localeRoutingEnabledCookieName` | Cookie that flags whether middleware locale routing is enabled | `generaltranslation.locale-routing-enabled` | +| `resetLocaleCookieName` | Cookie that resets the stored locale | `generaltranslation.locale-reset` | + +--- -### Render methods - * `skeleton`: Renders a fragment. - * `replace`: Renders content in default language while waiting. - * `default`: For locales with the same language (ie `en-US` and `en-GB`) behaves like replace. For locales with different languages (ie `en-US` and `fr`), behaves like skeleton. +## Dictionary detection [#dictionary-detection] -### Timeout -Timeouts only apply to runtime translations, or translations that need to be performed on demand as they have not been cached. +At build time, `gt-next` automatically detects a dictionary file named `dictionary.ts`, `dictionary.js`, or `dictionary.json` placed at the project root or in the `src` folder. +Use the `dictionary` prop to point to a custom filepath instead. -Timeouts are set to 8 seconds by default. -This design decision is to facilitate vercel users who have a default 10-second timeout for serverless functions on the free plan. +The default-locale dictionary is bundled with your app and loaded synchronously. +A custom [`loadDictionary`](/docs/next/api/config/load-dictionary) function only applies to non-default locales; the default locale always uses the bundled dictionary. --- ## Examples ### Render settings -This example configures `gt-next` to render a skeleton while waiting for translations to load. -If the translation takes longer than 8 seconds, the method will time out and render the default language content. +This example raises the runtime translation timeout to 10 seconds. +If a translation takes longer than that, `gt-next` renders the default language content instead. ```json title="gt.config.json" { @@ -243,7 +260,6 @@ const nextConfig = { export default withGTConfig(nextConfig, { renderSettings: { - method: 'skeleton', timeout: 10000, }, }); @@ -253,8 +269,9 @@ export default withGTConfig(nextConfig, { ## Notes * `withGTConfig` integrates GT translation functionality into your Next.js app and must be used in the root configuration file. - * Parameters like `apiKey` and `projectId` can be set directly in the configuration or as environment variables. - * Advanced parameters like `renderSettings` and `_batchInterval` allow fine-grained control over translation behavior and performance. + * API keys and project IDs are set through environment variables (`GT_API_KEY`, `GT_PROJECT_ID` or `NEXT_PUBLIC_GT_PROJECT_ID`, and `GT_DEV_API_KEY` or `NEXT_PUBLIC_GT_DEV_API_KEY`), not props. + * A `customMapping` belongs in [`gt.config.json`](/docs/next/api/config/gt-config-json), not in `withGTConfig` props. + * Advanced parameters like `renderSettings` and `batchInterval` allow fine-grained control over translation behavior and performance. ## Next steps * Add [translation to your CD process](/docs/next/tutorials/quickdeploy). diff --git a/docs/en-US/next/api/dictionary/get-translations.mdx b/docs/en-US/next/api/dictionary/get-translations.mdx index 2a569573..1e10671f 100644 --- a/docs/en-US/next/api/dictionary/get-translations.mdx +++ b/docs/en-US/next/api/dictionary/get-translations.mdx @@ -13,8 +13,8 @@ d('greeting.hello'); // pass the id to get a translation ``` `getTranslations` supports: - * Translation of string and jsx content. - * Variable insertion and conditional logic within translations. + * Translation of string content. + * Variable insertion within translations. * Optional id prefixing. For client-side translations, see [`useTranslations`](/docs/next/api/dictionary/use-translations). @@ -50,13 +50,13 @@ For client-side translations, see [`useTranslations`](/docs/next/api/dictionary/ A promise of a translation function `d` that, given an id, will return the translated version of the corresponding entry ```jsx -Promise<(id: string, options?: DictionaryTranslationOptions) => string> +Promise<(id: string, options?: TranslationVariables) => string> ``` | Name | Type | Description | |-----------------------|--|-----------------------------------------------------------------------------| | `id` | `string` | The id of the entry to be translated | -| `options?` | [`DictionaryTranslationOptions`](/docs/next/api/types/dictionary-translation-options) | Translation options to customize the behavior of `d`. | +| `options?` | [`TranslationVariables`](/docs/next/api/types/dictionary-translation-options) | Variables to interpolate into the translation, e.g., `{ userName: 'Alice' }`. | --- @@ -66,9 +66,9 @@ Promise<(id: string, options?: DictionaryTranslationOptions) => string> ### Basic dictionary usage Every entry in your dictionary gets translated. -```jsx title="dictionary.jsx" copy +```js title="dictionary.js" copy const dictionary = { - greeting: <>Hello, Alice!, // [!code highlight] + greeting: 'Hello, Alice!', // [!code highlight] }; export default dictionary; ``` @@ -98,7 +98,7 @@ In this example, we use `{}` to pass variables to the translations. In the dictionary, we assign identifier `{userName}`. -```jsx title="dictionary.jsx" copy +```js title="dictionary.js" copy // [!code word:userName] const dictionary = { greeting: "Hello, {userName}!", // [!code highlight] @@ -126,7 +126,7 @@ export default async function TranslateGreeting() { ### Using prefixes We can use prefixes to only fetch a subset of the dictionary. -```jsx title="dictionary.jsx" copy +```js title="dictionary.js" copy const dictionary = { prefix1: { // [!code highlight] prefix2: { // [!code highlight] @@ -140,7 +140,7 @@ Because we added the value `'prefix1.prefix2'` to the `getTranslations` method, ```jsx title="UserDetails.jsx" copy import { getTranslations } from 'gt-next/server'; -export default function UserDetails() { +export default async function UserDetails() { const d = await getTranslations('prefix1.prefix2'); // [!code highlight] return (
@@ -153,6 +153,8 @@ export default function UserDetails() { ## Notes * The `getTranslations` function allows you to access dictionary translations on the server side. + * If the default-locale dictionary has no entry for the given id, the translation function throws an error (`Dictionary entry ${id} cannot be found`). This happens in both development and production. + * If the default-locale entry exists but the target-locale translation is missing, the translation function falls back to the default-locale entry instead of throwing. ## Next steps * See [`useTranslations`](/docs/next/api/dictionary/use-translations) for the client-side equivalent of `getTranslations`. diff --git a/docs/en-US/next/api/dictionary/use-translations.mdx b/docs/en-US/next/api/dictionary/use-translations.mdx index 26e75d34..a78f12ae 100644 --- a/docs/en-US/next/api/dictionary/use-translations.mdx +++ b/docs/en-US/next/api/dictionary/use-translations.mdx @@ -44,16 +44,27 @@ For async components, see [`getTranslations`](/docs/next/api/dictionary/get-tran ### Returns -A translation function `d` that, given an id, will return the translated version of the corresponding entry +A translation function `t` that, given an id, returns the translated version of the corresponding entry ```jsx -(id: string, options?: DictionaryTranslationOptions) => string +(id: string, options?: TranslationVariables) => string ``` | Name | Type | Description | |-----------------------|--|-----------------------------------------------------------------------------| | `id` | `string` | The id of the entry to be translated | -| `options?` | [`DictionaryTranslationOptions`](/docs/next/api/types/dictionary-translation-options) | Translation options to customize the behavior of `d`. | +| `options?` | [`TranslationVariables`](/docs/next/api/types/dictionary-translation-options) | Variables to interpolate into the translated entry. | + +Metadata such as context does not go in the `t()` call. +Instead, it lives in the dictionary entry itself, e.g. `greeting: ['Hello!', { $context: 'a friendly greeting' }]`. + +### Throws + +`t(id)` and `t.obj(id)` throw an `Error` (`Dictionary entry ${id} cannot be found`) when the entry does not exist in the default locale's dictionary. +This applies in both development and production. + +If the source entry exists but the current locale's translation is missing, `t` does not throw. +It falls back to the source entry, translating it at runtime in development when possible. --- @@ -72,21 +83,24 @@ export default dictionary; When we want to access these entries (on the client side), we call `useTranslations`. This returns a function that accepts the key of a translation from the dictionary. +Place your dictionary in a `dictionary.js`, `dictionary.ts`, or `dictionary.json` file at the root of your project or in the `src/` directory. +See the [dictionaries guide](/docs/next/guides/dictionaries) for more information. + ```jsx title="TranslateGreeting.jsx" copy import { useTranslations } from 'gt-next'; -export default async function TranslateGreeting() { +export default function TranslateGreeting() { const t = useTranslations(); // [!code highlight] return (

- {t('greeting')} // Hello, Alice // [!code highlight] + {t('greeting')} // [!code highlight]

); } ``` ### Using variables [#variables] -In order to pass values, you must (1) assign an identifier and (2) reference the identifier when calling the `d` function. +In order to pass values, you must (1) assign an identifier and (2) reference the identifier when calling the `t` function. In this example, we use `{}` to pass variables to the translations. In the dictionary, we assign identifier `{userName}`. @@ -99,11 +113,11 @@ const dictionary = { export default dictionary; ``` -```jsx title="src/server/TranslateGreeting.jsx" copy +```jsx title="TranslateGreeting.jsx" copy // [!code word:userName] import { useTranslations } from 'gt-next'; -export default async function TranslateGreeting() { +export default function TranslateGreeting() { const t = useTranslations(); // Hello Alice! @@ -147,6 +161,9 @@ export default function UserDetails() { ## Notes * The `useTranslations` function allows you to access dictionary translations on the client side. * The `useTranslations` hook can only be used within a component wrapped by a [`` component](/docs/next/api/components/gtprovider). + * The `t()` function throws when the requested entry is missing from the default locale's dictionary. Make sure every id you reference exists in the source dictionary. + * When only the current locale's translation is missing, `t()` falls back to the source entry instead of throwing. + * Entry metadata (`$context`, `$format`, `$maxChars`) belongs in the dictionary entry, not in the `t()` call. ## Next steps * For server-side translations, see [`getTranslations`](/docs/next/api/dictionary/get-translations). diff --git a/docs/en-US/next/api/helpers/get-default-locale.mdx b/docs/en-US/next/api/helpers/get-default-locale.mdx index 7f5eff7d..c1d9d600 100644 --- a/docs/en-US/next/api/helpers/get-default-locale.mdx +++ b/docs/en-US/next/api/helpers/get-default-locale.mdx @@ -1,22 +1,19 @@ --- title: getDefaultLocale -description: API reference for the getDefaultLocale server-side method +description: API reference for the getDefaultLocale method --- ## Overview The `getDefaultLocale` function retrieves the application's default locale. -This locale is determined when the server starts and is used as the fallback language for translations. +This locale is used as the fallback language for translations. It returns a [locale code](/docs/core/locales), e.g., `'en'`. - - `getDefaultLocale` is a server-side method and can only be used on server-side - components. - +Import it from `gt-next`. It works in both server and client components. See [`withGTConfig`](/docs/next/api/config/with-gt-config) for configuration. If no default locale is specified in [`withGTConfig`](/docs/next/api/config/with-gt-config) it defaults to `'en'`. -For client-side, see [`useDefaultLocale`](/docs/next/api/helpers/use-default-locale). +In client components, you can also use the [`useDefaultLocale`](/docs/next/api/helpers/use-default-locale) hook. ## Reference @@ -33,7 +30,7 @@ A string representing the application's default locale, e.g., `'en'`. Retrieve the application's default locale and use it in your server-side logic. ```jsx title="GetDefaultLocale.jsx" copy -import { getDefaultLocale } from 'gt-next/server'; +import { getDefaultLocale } from 'gt-next'; export default function GetDefaultLocale() { const defaultLocale = getDefaultLocale(); // [!code highlight] @@ -46,7 +43,7 @@ export default function GetDefaultLocale() { ## Notes - The `getDefaultLocale` returns the default locale set in [`withGTConfig`](/docs/next/api/config/with-gt-config). -- `getDefaultLocale` is server-side only. +- `getDefaultLocale` works in both server and client components. - The returned locale adheres to the [locale code](/docs/core/locales) format. ## Next steps diff --git a/docs/en-US/next/api/helpers/get-locale-properties.mdx b/docs/en-US/next/api/helpers/get-locale-properties.mdx index c039a749..d6858ea4 100644 --- a/docs/en-US/next/api/helpers/get-locale-properties.mdx +++ b/docs/en-US/next/api/helpers/get-locale-properties.mdx @@ -1,17 +1,13 @@ --- title: getLocaleProperties -description: API reference for the getLocaleProperties server-side method +description: API reference for the getLocaleProperties method --- ## Overview -The `getLocaleProperties` function returns metadata about a given locale during server-side rendering, including its name, native name, language, region, and script information. +The `getLocaleProperties` function returns metadata about a given locale, including its name, native name, language, region, and script information. - - `getLocaleProperties` is a server-side method and can only be used in server components. - - -For client-side usage, see [`useLocaleProperties`](/docs/next/api/helpers/use-locale-properties). +Import it from `gt-next`. It works in both server and client components. In client components, you can also use the [`useLocaleProperties`](/docs/next/api/helpers/use-locale-properties) hook. ## Reference @@ -19,7 +15,7 @@ For client-side usage, see [`useLocaleProperties`](/docs/next/api/helpers/use-lo | Parameter | Type | Description | | --- | --- | --- | -| `locale` | `string` | A BCP 47 locale code (e.g., `'en-US'`, `'ja'`). | +| `locale` | `string` (optional) | A BCP 47 locale code (e.g., `'en-US'`, `'ja'`). Defaults to the current locale. | ### Returns @@ -50,7 +46,7 @@ A `LocaleProperties` object with the following fields: ### Basic usage ```jsx title="LocaleInfo.jsx" copy -import { getLocaleProperties } from 'gt-next/server'; +import { getLocaleProperties } from 'gt-next'; export default function LocaleInfo() { const props = getLocaleProperties('en-US'); // [!code highlight] diff --git a/docs/en-US/next/api/helpers/get-locales.mdx b/docs/en-US/next/api/helpers/get-locales.mdx index 9ad01816..43bdcd76 100644 --- a/docs/en-US/next/api/helpers/get-locales.mdx +++ b/docs/en-US/next/api/helpers/get-locales.mdx @@ -1,17 +1,13 @@ --- title: getLocales -description: API reference for the getLocales server-side method +description: API reference for the getLocales method --- ## Overview -The `getLocales` function retrieves the list of supported locales configured for your application during server-side rendering. +The `getLocales` function retrieves the list of supported locales configured for your application. - - `getLocales` is a server-side method and can only be used in server components. - - -For client-side usage, see [`useLocales`](/docs/next/api/helpers/use-locales). +Import it from `gt-next`. It works in both server and client components. In client components, you can also use the [`useLocales`](/docs/next/api/helpers/use-locales) hook. ## Reference @@ -26,7 +22,7 @@ For client-side usage, see [`useLocales`](/docs/next/api/helpers/use-locales). ### Basic usage ```jsx title="LocaleList.jsx" copy -import { getLocales } from 'gt-next/server'; +import { getLocales } from 'gt-next'; export default function LocaleList() { const locales = getLocales(); // [!code highlight] @@ -45,7 +41,7 @@ export default function LocaleList() { ## Notes - The supported locales are configured in your [`gt.config.json`](/docs/next/api/config/gt-config-json) file. -- `getLocales` is server-side only. For client components, use [`useLocales`](/docs/next/api/helpers/use-locales). +- `getLocales` works in both server and client components. ## Next steps diff --git a/docs/en-US/next/api/helpers/is-locale-supported.mdx b/docs/en-US/next/api/helpers/is-locale-supported.mdx index efd15829..bdbac16e 100644 --- a/docs/en-US/next/api/helpers/is-locale-supported.mdx +++ b/docs/en-US/next/api/helpers/is-locale-supported.mdx @@ -1,18 +1,15 @@ --- title: isLocaleSupported -description: API reference for the isLocaleSupported server-side method +description: API reference for the isLocaleSupported method --- ## Overview -The `isLocaleSupported` function checks whether a locale is valid and supported by your app's current gt-next configuration. +The `isLocaleSupported` function checks whether a locale is valid and supported by your app's current `gt-next` configuration. Use it when a route param or other request input should be explicitly rejected instead of silently falling back to the default locale. A common pattern is validating the `[locale]` segment in a dynamic route and calling `notFound()` when the value is not supported. - - `isLocaleSupported` is a server-side method and can only be used on - server-side components. - +Import it from `gt-next`. It works in both server and client components. ## Reference @@ -47,7 +44,7 @@ Validate the `[locale]` route param and call `notFound()` for unsupported locale ```tsx title="app/[locale]/page.tsx" copy import { notFound } from 'next/navigation'; -import { isLocaleSupported } from 'gt-next/server'; +import { isLocaleSupported } from 'gt-next'; export default async function Page({ params, @@ -68,7 +65,7 @@ export default async function Page({ ## Notes -- `isLocaleSupported` is server-side only. +- `isLocaleSupported` works in both server and client components. - Without this check, an invalid or unsupported request locale falls back to the default locale rather than throwing. See [`getLocale`](/docs/next/api/helpers/get-locale) for the fallback behavior. - The set of supported locales is configured in [`withGTConfig`](/docs/next/api/config/with-gt-config). See also [`gt.config.json`](/docs/next/api/config/gt-config-json). diff --git a/docs/en-US/next/api/strings/get-gt.mdx b/docs/en-US/next/api/strings/get-gt.mdx index b4b12ac4..c646d9a6 100644 --- a/docs/en-US/next/api/strings/get-gt.mdx +++ b/docs/en-US/next/api/strings/get-gt.mdx @@ -28,13 +28,13 @@ None A promise of a callback function, `gt`, which translates the provided content. ```jsx -Promise<(content: string, options?: InlineTranslationOptions) => string> +Promise<(content: string, options?: GTTranslationOptions) => string> ``` | Name | Type | Description | |-----------------------|--|-----------------------------------------------------------------------------| | `content` | `string` | The string content to be translated. | -| `options?` | [`InlineTranslationOptions`](/docs/next/api/types/inline-translation-options) | Translation options to customize the behavior of `gt`. | +| `options?` | [`GTTranslationOptions`](/docs/next/api/types/inline-translation-options) | Translation options to customize the behavior of `gt`. | --- diff --git a/docs/en-US/next/api/strings/get-messages.mdx b/docs/en-US/next/api/strings/get-messages.mdx index d4355fe0..a71b6507 100644 --- a/docs/en-US/next/api/strings/get-messages.mdx +++ b/docs/en-US/next/api/strings/get-messages.mdx @@ -69,7 +69,8 @@ i.e., using [`tx`](/docs/next/api/strings/tx) or [``](/docs/next/api/compone You can use `getMessages` to translate encoded strings from `msg`. ```javascript copy -import { msg, getMessages } from 'gt-next/server'; +import { getMessages } from 'gt-next/server'; +import { msg } from 'gt-next'; const encodedGreeting = msg('Hello, Alice!'); @@ -90,7 +91,8 @@ Note: "Alice" will be translated to the user's preferred language. You can pass variables to encoded strings. ```javascript copy -import { msg, getMessages } from 'gt-next/server'; +import { getMessages } from 'gt-next/server'; +import { msg } from 'gt-next'; const encodedGreeting = msg('Hello, {name}!'); @@ -109,7 +111,8 @@ export default async function TranslateGreeting() { When you pass variables to both `msg` and `m`, the variables passed to `msg` will override the variables passed to `m`. ```javascript copy -import { msg, getMessages } from 'gt-next/server'; +import { getMessages } from 'gt-next/server'; +import { msg } from 'gt-next'; const encodedGreeting = msg('Hello, {name}!', { name: 'Alice' }); @@ -129,7 +132,8 @@ Note: This will display "Hello, Alice!" - the variable is not overridden at rend `gt-next` supports ICU message format, which allows you to also format your variables. ```javascript copy -import { msg, getMessages } from 'gt-next/server'; +import { getMessages } from 'gt-next/server'; +import { msg } from 'gt-next'; const encodedMessage = msg('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count: 10 }); diff --git a/docs/en-US/next/api/types/dictionary-translation-options.mdx b/docs/en-US/next/api/types/dictionary-translation-options.mdx index 97d8336c..0e849383 100644 --- a/docs/en-US/next/api/types/dictionary-translation-options.mdx +++ b/docs/en-US/next/api/types/dictionary-translation-options.mdx @@ -1,18 +1,24 @@ --- -title: DictionaryTranslationOptions -description: API reference for the DictionaryTranslationOptions type +title: TranslationVariables +description: API reference for the TranslationVariables type --- ## Overview -The `DictionaryTranslationOptions` type is used to pass variables to dictionary entries and specify their render behavior. +The `TranslationVariables` type is used to pass interpolation variables to dictionary entries. It is used with [`useTranslations`](/docs/next/api/dictionary/use-translations) and [`getTranslations`](/docs/next/api/dictionary/get-translations) to pass variables to dictionary entries. +This page formerly documented the `DictionaryTranslationOptions` type, which no longer exists. + +Entry metadata such as `$context` is not passed to the `t()` call. +Instead, it lives in the dictionary entry itself (typed `DictionaryEntryOptions`), e.g. `greeting: ['Hello!', { $context: 'a friendly greeting' }]`. + -**Buildtime Translation:** -Variables are not translated with [`useTranslations`](/docs/next/api/dictionary/use-translations) and [`getTranslations`](/docs/next/api/dictionary/get-translations), only the original string. -See [`tx`](/docs/next/api/strings/tx) for translating strings with dynamic content. + **Buildtime Translation:** + `useTranslations` and `getTranslations` translations occur at buildtime; however, variables are never translated. + Instead, they are inserted into the translation with formatting. + Make sure to follow the [deployment guide here](/docs/next/tutorials/quickdeploy). @@ -23,8 +29,8 @@ See [`tx`](/docs/next/api/strings/tx) for translating strings with dynamic conte ', optional: true, default: 'undefined', }, @@ -35,7 +41,25 @@ See [`tx`](/docs/next/api/strings/tx) for translating strings with dynamic conte | Prop | Description | | ---- | ----------- | -| `[variable]` | Variables are passed as top-level keys in the options object. The key names correspond to placeholders in the dictionary entry (e.g., `{username}`). | +| `variables` | An object where the keys identify where each value is mapped to in the dictionary entry.| + +### Entry metadata + +Metadata for a dictionary entry is defined on the entry itself with the `DictionaryEntryOptions` type, not passed to `t()`. + +| Field | Description | +| ----- | ----------- | +| `$context` | Additional context for the entry, used to refine the translation. | +| `$format` | The data format for the entry (e.g. `'ICU'`). Defaults to `'ICU'`. | +| `$maxChars` | Limits the character count of the translation. | + +```jsx title="dictionary.ts" +const dictionary = { + greeting: ['Hello!', { $context: 'a friendly greeting' }], +}; + +export default dictionary; +``` --- @@ -44,7 +68,7 @@ See [`tx`](/docs/next/api/strings/tx) for translating strings with dynamic conte ### Passing variables -In order to pass a variable to the dictionary entry, we need to do two things: (1) add a variable to the entry and (2) reference said variable in the [`d`](/docs/next/api/strings/use-gt) invocation. +In order to pass a variable to the dictionary entry, we need to do two things: (1) add a variable to the entry and (2) reference said variable in the [`t`](/docs/next/api/dictionary/use-translations) invocation. First, we add a variable to the dictionary entry with the following syntax: `{username}`. `username` is the name of the variable. @@ -108,9 +132,11 @@ const Component = () => { --- ## Notes - * Variables are passed as top-level keys in the options object, not nested under a `variables` key. + * `TranslationVariables` was formerly named `DictionaryTranslationOptions`. + * The `variables` object passes values to a dictionary entry. + * Entry metadata (`$context`, `$format`, `$maxChars`) belongs in the dictionary entry itself, typed as `DictionaryEntryOptions`. -### Next steps +## Next steps * See [dictionaries](/docs/next/guides/dictionaries) for more information on dictionaries and common practices. * See [`useTranslations`](/docs/next/api/dictionary/use-translations) or [`getTranslations`](/docs/next/api/dictionary/get-translations) for more information on dictionaries interface. * See [`ICU message format`](https://unicode-org.github.io/icu/userguide/format_parse/messages/) for more information on formatting options. diff --git a/docs/en-US/next/api/types/inline-translation-options.mdx b/docs/en-US/next/api/types/inline-translation-options.mdx index 73557426..670d31a8 100644 --- a/docs/en-US/next/api/types/inline-translation-options.mdx +++ b/docs/en-US/next/api/types/inline-translation-options.mdx @@ -1,18 +1,24 @@ --- -title: InlineTranslationOptions -description: API reference for the InlineTranslationOptions type +title: GTTranslationOptions +description: API reference for the GTTranslationOptions type --- ## Overview -The `InlineTranslationOptions` type is used to pass variables to inline translations and specify their render behavior. +The `GTTranslationOptions` type is used to pass variables to inline translations and provide metadata for the translation. You can also add context and an identifier to the translation. It is used with [`useGT`](/docs/next/api/strings/use-gt), [`getGT`](/docs/next/api/strings/get-gt), and [`msg`](/docs/next/api/strings/msg) to pass variables to inline string translations. +This type was formerly named `InlineTranslationOptions`. + +`GTTranslationOptions` combines interpolation variables (`TranslationVariables`) with `$`-prefixed metadata fields. +It is exported from `gt-next`. + **Buildtime Translation:** - Variables are not translated with `useGT`, `getGT`, and `msg`, only the original string. - See [`tx`](/docs/next/api/strings/tx) for translating strings with dynamic content. + `useGT`, `getGT`, and `msg` translations occur at buildtime; however, variables are never translated. + Instead, they are inserted into the translation with formatting. + Make sure to follow the [deployment guide here](/docs/next/tutorials/quickdeploy). ## Reference @@ -21,8 +27,8 @@ It is used with [`useGT`](/docs/next/api/strings/use-gt), [`getGT`](/docs/next/a ', optional: true, default: 'undefined', }, @@ -36,6 +42,16 @@ It is used with [`useGT`](/docs/next/api/strings/use-gt), [`getGT`](/docs/next/a optional: true, default: 'undefined', }, + "$format?": { + type: 'string', + optional: true, + default: "'ICU'", + }, + "$locale?": { + type: 'string', + optional: true, + default: 'undefined', + }, "$maxChars?": { type: 'number', optional: true, @@ -53,11 +69,13 @@ It is used with [`useGT`](/docs/next/api/strings/use-gt), [`getGT`](/docs/next/a | Prop | Description | | ---- | ----------- | -| `[variable]` | Variables are passed as top-level keys in the options object. The key names correspond to placeholders in the string (e.g., `{username}`). | -| `$context` | Provide context for the content to guide translation. | -| `$id` | Provide an identifier for use with the translation editor. | -| `$maxChars` | Limit the character count of the translation. The library strictly enforces this limit. | -| `$requiresReview` | When `true`, the translation is withheld from serving until it is approved in a human-review step. Must be a boolean literal. | +| `variables` | An object where the keys identify where each value is mapped to in the string.| +| `$context` | Additional context for the content, used to refine the translation. | +| `$id` | An identifier for the message, used as descriptive metadata on the GT platform. | +| `$format` | The data format for the message (e.g. `'ICU'`). Defaults to `'ICU'`. | +| `$locale` | The locale to use for the translation. Defaults to the current locale. | +| `$maxChars` | Limits the character count of the translation. The library strictly enforces this limit using `formatCutoff()` logic. | +| `$requiresReview` | Gates the translation behind a human-review step before it is served. Must be a boolean literal. | --- @@ -146,8 +164,10 @@ const Component = () => { --- ## Notes - * `InlineTranslationOptions` is used for inline string translations. - * Variables are passed as top-level keys in the options object, not nested under a `variables` key. + * `GTTranslationOptions` is used for inline string translations. + * `GTTranslationOptions` was formerly named `InlineTranslationOptions`. + * Keys without a `$` prefix are interpolation variables that pass values to the text. + * Keys with a `$` prefix are metadata for the translation. ## Next steps diff --git a/docs/en-US/next/api/types/runtime-translation-options.mdx b/docs/en-US/next/api/types/runtime-translation-options.mdx index cf378753..f3f10362 100644 --- a/docs/en-US/next/api/types/runtime-translation-options.mdx +++ b/docs/en-US/next/api/types/runtime-translation-options.mdx @@ -50,6 +50,7 @@ This is used with the [`tx`](/docs/next/api/strings/tx) function. | ---- | ----------- | | `[variable]` | Variables are passed as top-level keys in the options object. The key names correspond to placeholders in the string (e.g., `{username}`). | | `$locale` | Specify a locale for the translation. Will default to browser's most preferred locale that is supported by your app. | +| `$context` | Additional context to aid the translation. | | `$maxChars` | Limit the character count of the translation. The library strictly enforces this limit. | diff --git a/docs/en-US/next/concepts/environments.mdx b/docs/en-US/next/concepts/environments.mdx index 921fc34f..a5520ba8 100644 --- a/docs/en-US/next/concepts/environments.mdx +++ b/docs/en-US/next/concepts/environments.mdx @@ -14,7 +14,11 @@ It detects the environment by checking the `NODE_ENV` environment variable. ### Environment variables -In production, `gt-next` will only read the `GT_PROJECT_ID` and `GT_API_KEY` environment variables. +`gt-next` reads credentials from environment variables only — API keys and project IDs cannot be passed to `withGTConfig()` as configuration options in code. + +In production, `gt-next` uses your project ID to load translations from the General Translation CDN. Set it with the `GT_PROJECT_ID` environment variable in server environments. Client-side code only receives the project ID through `NEXT_PUBLIC_GT_PROJECT_ID` — a bare `GT_PROJECT_ID` is never exposed to the client bundle. + +Server environments also read a production API key from `GT_API_KEY`. Never expose an API key to client-side code. The API Key must be a Production API Key, beginning with `gtx-api-`. @@ -34,9 +38,9 @@ On-demand translation for dynamic content using the `` component or `tx` fun ### Environment variables -`gt-next` will accept the `GT_PROJECT_ID` and `GT_API_KEY` environment variables. +In development, `gt-next` also reads a development API key from the environment to enable translation hot reloading and on-demand translation. Set `GT_DEV_API_KEY` in server environments, or `NEXT_PUBLIC_GT_DEV_API_KEY` to expose it to client-side code. -The API key can either be a Production API Key, beginning with `gtx-api-`, or a Development API Key, beginning with `gtx-dev-`. +Development API keys are intended for local development only — never set one in a production environment. If a production API key is provided in development, `gt-next` will behave as if you are in production. This means that translation hot reloading will be disabled, and components without translations will render the original content. diff --git a/docs/en-US/next/guides/cache-components.mdx b/docs/en-US/next/guides/cache-components.mdx index 6a39f2ec..14e65d48 100644 --- a/docs/en-US/next/guides/cache-components.mdx +++ b/docs/en-US/next/guides/cache-components.mdx @@ -53,9 +53,22 @@ export default async function getRegion(): Promise { **Do not use `headers()` in your `getLocale` or `getRegion` functions.** Calling `headers()` inside a `"use cache"` boundary causes a build error. Use `next/root-params` as shown above. - -`experimentalLocaleResolution` is deprecated as of gt-next@6.16.29. It relies on unsupported Next.js internals and may break in future Next.js releases. Use explicit `getLocalePath` and `getRegionPath` configuration instead. - + + + ### Configure a custom `loadTranslations` + +With `cacheComponents` enabled, `gt-next` requires a custom [`loadTranslations`](/docs/next/api/config/load-translations) function — the build fails without one, because the default remote translation loader cannot be used safely with Cache Components. + +Add a `loadTranslations.ts` file to your project root (or configure `loadTranslationsPath` in `withGTConfig`), and store your translations locally. See the [local translations guide](/docs/next/guides/local-tx) for the full setup. + +```ts title="loadTranslations.ts" +export default async function loadTranslations(locale: string) { + const translations = await import(`./public/locales/${locale}.json`); + return translations.default; +} +``` + +If your loader performs dynamic loading, mark it with `"use cache"`. @@ -71,7 +84,7 @@ export const config = { matcher: ['/((?!api|static|.*\\..*|_next).*)'] }; -```` +``` ### Add the `locale` parameter to cached components with translatable content @@ -88,7 +101,7 @@ export default async function Page() { const locale = await getLocale() return } -```` +``` @@ -98,6 +111,8 @@ export default async function Page() { - When using custom `getLocalePath` and `getRegionPath`, those functions handle locale and region resolution for cached components. - The `next/root-params` API allows reading route parameters like `[locale]` from anywhere in the component tree, including inside `"use cache"` boundaries. The root param value automatically becomes part of the cache key. - The `[locale]` segment must be a root parameter (no `app/layout.tsx` above it). +- With `cacheComponents` enabled, `gt-next` delegates caching to Next.js: it forces its own translation cache expiry off (`cacheExpiryTime: 0`). +- Development runtime translation hot reload is disabled when `cacheComponents` is enabled, because it performs dynamic requests that are not allowed with Cache Components. Use local translations during development instead. --- diff --git a/docs/en-US/next/guides/dictionaries.mdx b/docs/en-US/next/guides/dictionaries.mdx index 3b81d06a..63945694 100644 --- a/docs/en-US/next/guides/dictionaries.mdx +++ b/docs/en-US/next/guides/dictionaries.mdx @@ -112,7 +112,7 @@ function MyComponent() { import { getTranslations } from 'gt-next/server'; async function MyServerComponent() { - const d = await getTranslations(); + const t = await getTranslations(); return (
@@ -261,6 +261,10 @@ This loads JSON translation files from your `public/locales/` directory: **Choose the right approach:** Use [`loadTranslations`](/docs/next/api/config/load-translations) for new projects with automatic translation generation, or [`loadDictionary`](/docs/next/api/config/load-dictionary) when migrating existing translation files. + + **Default locale:** The default-locale dictionary is bundled with your app at build time and loaded synchronously. A custom `loadDictionary` function is only called for non-default locales. + + ## Production setup ### Build process diff --git a/docs/en-US/next/guides/dynamic-content.mdx b/docs/en-US/next/guides/dynamic-content.mdx index 856810ff..5922b56c 100644 --- a/docs/en-US/next/guides/dynamic-content.mdx +++ b/docs/en-US/next/guides/dynamic-content.mdx @@ -29,7 +29,7 @@ Dynamic translation is for content that truly cannot be known at build time: ### JSX content with Tx ```jsx -import { Tx } from 'gt-next'; +import { Tx } from 'gt-next/server'; async function UserPost({ postContent }) { return ( @@ -78,7 +78,7 @@ function ClientComponent() { ### User-generated content ```jsx -import { Tx } from 'gt-next'; +import { Tx } from 'gt-next/server'; async function ChatMessage({ message }) { return ( @@ -108,7 +108,8 @@ async function NewsArticle({ article }) { ### Mixed content ```jsx -import { T, Tx, Var } from 'gt-next'; +import { T, Var } from 'gt-next'; +import { Tx } from 'gt-next/server'; async function ProductReview({ review }) { return ( @@ -136,7 +137,7 @@ import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { const { text, locale } = await request.json(); - const translated = await tx(text, { locale }); + const translated = await tx(text, { $locale: locale }); return NextResponse.json({ translated }); } ``` diff --git a/docs/en-US/next/guides/languages.mdx b/docs/en-US/next/guides/languages.mdx index 557f012f..ee99c2a3 100644 --- a/docs/en-US/next/guides/languages.mdx +++ b/docs/en-US/next/guides/languages.mdx @@ -17,7 +17,7 @@ Language switching allows users to change their preferred locale for your applic The [`useSetLocale`](/docs/next/api/helpers/use-set-locale) hook is a client-side hook that allows you to change the language of your app: ```tsx -import { useSetLocale } from 'gt-next/client'; +import { useSetLocale } from 'gt-next'; export default function MyComponent() { const setLocale = useSetLocale(); @@ -33,7 +33,7 @@ Simply provide the locale you want to change to as the argument to the function The [``](/docs/next/api/components/locale-selector) component provides a ready-to-use dropdown that automatically shows all configured locales: ```tsx -import { LocaleSelector } from 'gt-next/client'; +import { LocaleSelector } from 'gt-next'; export default function MyComponent() { return ; @@ -51,7 +51,7 @@ This component automatically: If you want to build your own custom locale selector component, use [`useLocaleSelector`](/docs/next/api/helpers/use-locale-selector): ```tsx -import { useLocaleSelector } from 'gt-next/client'; +import { useLocaleSelector } from 'gt-next'; function CustomLocaleSelector() { const { @@ -100,7 +100,7 @@ All language switching hooks and components must be used in client components ma ```tsx 'use client'; -import { useSetLocale } from 'gt-next/client'; +import { useSetLocale } from 'gt-next'; function LanguageSwitcher() { const setLocale = useSetLocale(); diff --git a/docs/en-US/next/guides/locale-aliases.mdx b/docs/en-US/next/guides/locale-aliases.mdx index 4d3f4b55..7304a776 100644 --- a/docs/en-US/next/guides/locale-aliases.mdx +++ b/docs/en-US/next/guides/locale-aliases.mdx @@ -50,10 +50,10 @@ While aliases work seamlessly for routing, there are three places where you **mu 2. Alternate link tags in your page metadata 3. Alternate entries in your sitemap -GT provides the `resolveCanonicalLocale()` method to convert aliases back to their BCP 47 codes. You can access it via `getGTClass` from `gt-next/server`: +GT provides the `resolveCanonicalLocale()` method to convert aliases back to their BCP 47 codes. You can access it via `getGTClass` from `gt-next`, which returns a `GTRuntime` instance with translation, formatting, and locale utilities. (The full `GT` class, which adds the project and file-management API client, remains available from `generaltranslation`.) ```ts -import { getGTClass } from 'gt-next/server'; +import { getGTClass } from 'gt-next'; const gtInstance = getGTClass(); const canonicalLocale = gtInstance.resolveCanonicalLocale('cn'); @@ -74,7 +74,7 @@ The `` attribute tells browsers and search engines what language the In your root layout, resolve the locale before passing it to the `` tag: ```tsx title="app/[locale]/layout.tsx" -import { getGTClass } from 'gt-next/server'; +import { getGTClass } from 'gt-next'; export default function RootLayout({ children, @@ -102,7 +102,7 @@ Alternate links tell search engines which versions of a page exist in other lang ```tsx title="app/[locale]/layout.tsx" import type { Metadata } from 'next'; -import { getGTClass } from 'gt-next/server'; +import { getGTClass } from 'gt-next'; export async function generateMetadata({ params, @@ -149,7 +149,7 @@ If you use a [dynamic sitemap](https://nextjs.org/docs/app/api-reference/file-co ```ts title="app/sitemap.ts" import type { MetadataRoute } from 'next'; -import { getGTClass } from 'gt-next/server'; +import { getGTClass } from 'gt-next'; export default function sitemap(): MetadataRoute.Sitemap { const gtInstance = getGTClass(); diff --git a/docs/en-US/next/guides/ssg.mdx b/docs/en-US/next/guides/ssg.mdx index 01fc9e6e..7ab836d7 100644 --- a/docs/en-US/next/guides/ssg.mdx +++ b/docs/en-US/next/guides/ssg.mdx @@ -91,7 +91,7 @@ export default async function getRegion() { Make sure you have [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params) configured for your locales. ```tsx title="page.tsx" -import { getLocales } from 'gt-next/server'; +import { getLocales } from 'gt-next'; export async function generateStaticParams() { return getLocales().map((locale) => ({ locale })); @@ -207,11 +207,12 @@ import('next/root-params').locale() inside a Route Handler. Next.js metadata image routes (`opengraph-image.tsx`, `twitter-image.tsx`) are Route Handlers internally, and `next/root-params` is not supported in Route Handlers. This means `getLocale()`, `getMessages()`, and `getGT()` will fail in these contexts. -**Fix:** Use `registerLocale()` to explicitly set the locale at the top of the handler: +**Fix:** Use `registerLocale()` to explicitly set the locale at the top of the handler, before any other `gt-next` calls: ```tsx title="app/[locale]/opengraph-image.tsx" import { ImageResponse } from 'next/og'; -import { registerLocale, getMessages, msg } from 'gt-next/server'; +import { registerLocale, getMessages } from 'gt-next/server'; +import { msg } from 'gt-next'; const HEADING = msg('Welcome to our site'); diff --git a/docs/en-US/next/tutorials/translating-strings.mdx b/docs/en-US/next/tutorials/translating-strings.mdx index 6a06dbd2..56af601d 100644 --- a/docs/en-US/next/tutorials/translating-strings.mdx +++ b/docs/en-US/next/tutorials/translating-strings.mdx @@ -34,7 +34,7 @@ export default function MyComponent() { ### Server-side components For any server-side strings, use [`getGT`](/docs/next/api/strings/get-gt). -```jsx title="src/pages/index.jsx" copy +```jsx title="src/app/page.jsx" copy import { getGT } from 'gt-next/server'; export default async function Home() { @@ -46,12 +46,6 @@ export default async function Home() { ); } ``` - - **Note:** - When in development, if you are translating content at runtime, you will have to refresh the page to see the translated version of a string from [`getGT`](/docs/next/api/strings/get-gt). - **This does not happen in production.** - - ### Adding variables Variables are values that may change, but do not get translated. To add variables to your strings, use the following pattern: diff --git a/docs/en-US/node/api/get-gt.mdx b/docs/en-US/node/api/get-gt.mdx index dadbbd7c..47cd7899 100644 --- a/docs/en-US/node/api/get-gt.mdx +++ b/docs/en-US/node/api/get-gt.mdx @@ -31,17 +31,17 @@ None. A promise that resolves to a translation function `gt`: ```ts -Promise<(content: string, options?: InlineTranslationOptions) => string> +Promise<(content: string, options?: GTTranslationOptions) => string> ``` | Name | Type | Description | | ---- | ---- | ----------- | | `content` | `string` | The string to translate. | -| `options?` | `InlineTranslationOptions` | Optional translation options (variables, context, etc.). | +| `options?` | `GTTranslationOptions` | Optional translation options (variables, context, etc.). | The `gt` function returns the translated string, or the original string if no translation is found. -#### `InlineTranslationOptions` +#### `GTTranslationOptions` | Prop | Type | Description | | ---- | ---- | ----------- | diff --git a/docs/en-US/node/api/get-messages.mdx b/docs/en-US/node/api/get-messages.mdx index 8db7defe..b0b56d26 100644 --- a/docs/en-US/node/api/get-messages.mdx +++ b/docs/en-US/node/api/get-messages.mdx @@ -35,13 +35,13 @@ None. A promise that resolves to a message resolution function `m`: ```ts -Promise<(encodedMsg: string | null | undefined, options?: InlineResolveOptions) => string | null | undefined> +Promise<(encodedMsg: string | null | undefined, options?: GTTranslationOptions) => string | null | undefined> ``` | Name | Type | Description | | ---- | ---- | ----------- | | `encodedMsg` | `string \| null \| undefined` | An encoded message string returned by `msg()`. Returns `null`/`undefined` if given `null`/`undefined`. | -| `options?` | `InlineResolveOptions` | Optional variable values to interpolate into the resolved message. | +| `options?` | `GTTranslationOptions` | Optional variable values to interpolate into the resolved message. | --- diff --git a/docs/en-US/node/api/get-translations.mdx b/docs/en-US/node/api/get-translations.mdx index 6844cded..f14555e1 100644 --- a/docs/en-US/node/api/get-translations.mdx +++ b/docs/en-US/node/api/get-translations.mdx @@ -24,7 +24,9 @@ t('greeting.hello'); // "Hello!" ### Parameters -None. +| Name | Type | Description | +| --- | --- | --- | +| `rootId?` | `string` | An optional prefix prepended to every key passed to `t` (e.g. `getTranslations('errors')` makes `t('notFound')` resolve `errors.notFound`). | ### Returns @@ -34,17 +36,17 @@ A promise that resolves to a translation function `t`: Promise ``` -The `t` function accepts a dictionary key and optional interpolation options: +The `t` function accepts a dictionary key and optional interpolation variables: | Name | Type | Description | | --- | --- | --- | | `id` | `string` | The dot-separated path to a dictionary entry. | -| `options?` | `DictionaryTranslationOptions` | Variables for interpolation. | +| `options?` | `TranslationVariables` | Variables for interpolation. | -**Returns:** `string` — the translated (or source-language fallback) text. +**Returns:** `string` — the translated (or default-locale fallback) text. -If the key does not exist in the source dictionary, `t()` throws an error. -If the key exists in the source dictionary but has no translation for the current locale, `t()` returns the source text. +If the key does not exist in the default-locale dictionary, `t()` throws `Dictionary entry ${id} cannot be found` — in development and in production. +If the key exists in the default-locale dictionary but has no translation for the current locale, `t()` falls back to the default-locale entry. ### `t.obj()` @@ -79,7 +81,7 @@ Create a `dictionary.json` file in your project root: } ``` -When you run `npx gtx translate`, the CLI automatically detects `dictionary.json` and translates it for your configured locales. +When you run `npx gt translate`, the CLI automatically detects `dictionary.json` and translates it for your configured locales. Then initialize GT with the dictionary: diff --git a/docs/en-US/node/api/initialize-gt.mdx b/docs/en-US/node/api/initialize-gt.mdx index af708d90..2e6e521a 100644 --- a/docs/en-US/node/api/initialize-gt.mdx +++ b/docs/en-US/node/api/initialize-gt.mdx @@ -33,7 +33,7 @@ initializeGT({ "defaultLocale?": { type: 'string', optional: true, - default: "'en-US'", + default: "'en'", }, "locales?": { type: 'string[]', @@ -43,6 +43,10 @@ initializeGT({ type: 'string', optional: true, }, + "apiKey?": { + type: 'string', + optional: true, + }, "devApiKey?": { type: 'string', optional: true, @@ -71,12 +75,8 @@ initializeGT({ type: 'Record>', optional: true, }, - "enableI18n?": { - type: 'boolean', - optional: true, - }, "cacheExpiryTime?": { - type: 'number', + type: 'number | null', optional: true, }, }} @@ -86,9 +86,10 @@ initializeGT({ | Prop | Description | | ---- | ----------- | -| `defaultLocale` | The default locale for your application. Defaults to `'en-US'`. | +| `defaultLocale` | The default locale for your application. Defaults to `'en'`. | | `locales` | An array of locale codes your application supports. | | `projectId` | Your General Translation project ID, required for cloud translation services. | +| `apiKey` | Production API key for cloud translation services. | | `devApiKey` | API key for development environment on-demand translations. | | `cacheUrl` | URL of the GT cache service. Set to `null` to disable. | | `runtimeUrl` | URL of the GT runtime translation service. Set to `null` to disable. | @@ -96,8 +97,7 @@ initializeGT({ | `loadDictionary` | An async function that loads a translated dictionary for a given locale. Requires `dictionary` to be set. | | `loadTranslations` | A custom function to load translations from your own source. | | `customMapping` | A mapping of custom locale codes to standard locale codes or locale properties. | -| `enableI18n` | Whether to enable i18n features. | -| `cacheExpiryTime` | Time in milliseconds before cached translations expire. | +| `cacheExpiryTime` | Time in milliseconds before cached translations expire. Set to `null` to disable expiry. | ### Returns diff --git a/docs/en-US/node/api/strings/msg.mdx b/docs/en-US/node/api/strings/msg.mdx index 88c5fb32..bbdb4334 100644 --- a/docs/en-US/node/api/strings/msg.mdx +++ b/docs/en-US/node/api/strings/msg.mdx @@ -44,7 +44,7 @@ console.log(decodedString); // "Hello, world!" | Name | Type | Description | |-----------------------|--|-----------------------------------------------------------------------------| | `content` | `string` | The string content to be encoded. | -| `options?` | [`InlineTranslationOptions`](/docs/next/api/types/inline-translation-options) | Translation options to customize the behavior of `msg`. | +| `options?` | [`GTTranslationOptions`](/docs/next/api/types/inline-translation-options) | Translation options to customize the behavior of `msg`. | ### Returns diff --git a/docs/en-US/react-native/api/components/gtprovider.mdx b/docs/en-US/react-native/api/components/gtprovider.mdx index e73d5d80..92fd6828 100644 --- a/docs/en-US/react-native/api/components/gtprovider.mdx +++ b/docs/en-US/react-native/api/components/gtprovider.mdx @@ -6,90 +6,62 @@ description: API reference for the GTProvider component ## Overview The `` component provides General Translation (GT) context to its children, enabling them to access translated content. -It is required for any client-side translations on your application. +It is required for any translations in your app. + +`` takes no configuration props. +Instead, configure the library by calling [`initializeGT()`](#initializing-the-library) in your app's entry file — the provider reads its configuration from there. + +Unlike the `gt-react` and `gt-next` providers, `` loads translations asynchronously and keeps a loading state. +While translations load, it renders the `fallback` prop (a spinner by default). ### When to use -- Wrap your entire application in `` to enable translations on the client. +- Wrap your entire application in `` to enable translations. - The `` component is used for both [inline ``](/docs/react-native/guides/t) and [dictionaries](/docs/react-native/guides/dictionaries). +--- + ## Reference ### Props ', optional: true, }, - 'loadTranslations?': { - type: '(locale: string) => Promise>', + 'onMissingTranslation?': { + type: '(lookup: TranslateLookup) => void', optional: true, }, - 'loadDictionary?': { - type: '(locale: string) => Promise>', + 'onMissingDictionaryEntry?': { + type: '(lookup: DictionaryLookup) => void', optional: true, }, - 'region?': { - type: 'string', - optional: true, - }, - 'fallback?': { - type: 'ReactNode', - optional: true, - }, - 'customMapping?': { - type: 'CustomMapping', + 'onMissingDictionaryObj?': { + type: '(lookup: DictionaryLookup) => void', optional: true, }, }} @@ -97,145 +69,131 @@ It is required for any client-side translations on your application. ### Description -| Prop | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `children` | Any component or the parents of any component that needs to translate or access translation information on the client side. These should include any components using ``, `useGT`, or other translation utilities. | -| `projectId?` | The project ID required for General Translation cloud services. | -| `dictionary?` | The translation dictionary for the project. | -| `locales?` | The list of approved locales for the project. | -| `defaultLocale?` | The default locale to use if no other locale is found. | -| `locale?` | The current locale, if already set. | -| `cacheUrl?` | The URL of the cache service for fetching translations. | -| `runtimeUrl?` | The URL of the runtime service for fetching translations. | -| `renderSettings?` | The settings for rendering translations. | -| `_versionId?` | The version ID for fetching translations. | -| `devApiKey?` | The API key for development environments. | -| `config?` | A configuration object (typically imported from `gt.config.json`) containing `projectId`, `locales`, `defaultLocale`, and other settings. An alternative to passing these as individual props. | -| `loadTranslations?` | An async function that takes a locale string and returns the translations object for that locale. Used to load pre-generated translation files at runtime. | -| `loadDictionary?` | An async function that takes a locale string and returns the dictionary translations for that locale. | -| `region?` | The user's region code (e.g., `US`, `GB`). Used for region-specific formatting. | -| `fallback?` | Custom fallback content to display while translations are loading. | -| `customMapping?` | A mapping of custom component names to their React components, used when rendering translated JSX. | +| Prop | Description | +| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `children?` | Your app. Any component that renders translations or reads translation state must be a descendant of ``. | +| `locale?` | Pin the app to a specific locale, or provide an ordered list of locale candidates. When omitted, the provider uses the locale persisted in native storage, falling back to the device locales. Candidates are matched against the `locales` you configure in `initializeGT()`. | +| `region?` | Override the user's region (e.g. `US`). When omitted, the provider uses the region persisted in native storage. | +| `enableI18n?` | Override whether translation is enabled. When omitted, the provider uses the value persisted in native storage, defaulting to `true`. | +| `fallback?` | Content rendered while translations load. Defaults to a centered spinner (`ActivityIndicator`). The fallback renders inside the GT context, so it can safely contain translation components and hooks. | +| `dictionaries?` | Preloaded dictionary translations, keyed by locale, for use with [`useTranslations`](/docs/react-native/api/dictionary/use-translations). | +| `onMissingTranslation?` | Advanced: overrides the default behavior when a translation is missing for the active locale. | +| `onMissingDictionaryEntry?` | Advanced: overrides the default behavior when a dictionary entry is missing. | +| `onMissingDictionaryObj?` | Advanced: overrides the default behavior when a dictionary object lookup fails. | ### Returns -`React.JSX.Element|undefined` containing the children that were passed to this component. +`React.JSX.Element` containing the children passed to the component, or the `fallback` while translations load. + +--- ## Examples -### Basic usage +### Initializing the library [#initializing-the-library] -Wrap your application in `` to add translation to your app. -Don't forget to add a [list of supported locales](/docs/platform/supported-locales) to enable translation. +Call `initializeGT()` in your entry file, before your app is registered. +Pass your configuration and translation loader there — `` picks them up automatically: -```jsx title="App.tsx" copy -import { GTProvider } from 'gt-react-native'; +```ts title="index.ts" copy +import { registerRootComponent } from 'expo'; +import { initializeGT } from 'gt-react-native'; +import App from './App'; import gtConfig from './gt.config.json'; -import { loadTranslations } from './loadTranslations'; +import esTranslations from './content/es.json'; +import frTranslations from './content/fr.json'; + +const localTranslations = { + es: esTranslations, + fr: frTranslations, +}; + +initializeGT({ + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, + loadTranslations: async (locale) => localTranslations[locale] ?? {}, +}); + +registerRootComponent(App); +``` + +Then wrap your app in `` — no props required: + +```tsx title="App.tsx" copy +import { Text } from 'react-native'; +import { GTProvider, T } from 'gt-react-native'; export default function App() { return ( - {/* // [!code highlight] */} - {/* Your app content */} + + + This gets translated automatically. + ); } ``` -### Dictionaries +### Custom loading fallback -You can also pass a dictionary to the `` component and then access it with the [`useTranslations`](/docs/react-native/api/dictionary/use-translations) hook. +While translations load, `` renders the `fallback` prop instead of your app. +Pass any component, such as a splash screen: -```jsx title="App.tsx" copy +```tsx title="App.tsx" copy import { GTProvider } from 'gt-react-native'; -import gtConfig from './gt.config.json'; -import { loadTranslations } from './loadTranslations'; -import dictionary from './dictionary'; +import SplashScreen from './SplashScreen'; export default function App() { return ( - {/* // [!code highlight] */} + }> {/* // [!code highlight] */} {/* Your app content */} ); } ``` -For more information on using dictionaries, check out this [guide](/docs/react-native/guides/dictionaries). +Because the fallback renders inside the GT context, you can use your app itself as the fallback. +The app appears immediately in the source language, and translations swap in once they finish loading: -### Adding configuration - -If you're not a fan of passing props directly to the `` component, you can create a configuration file and pass it to the component. -It also directly integrates with the [`gt translate` command](/docs/cli/translate), so you don't have to specify things like locales manually as a parameter. - -```json title="gt.config.json" copy -{ - "projectId": "your-project-id", - "locales": ["es", "fr"], - "defaultLocale": "en-US", - "_versionId": "translation-version-id" // allows for rolling back to previous translations (autogenerated by the CLI) -} -``` - -All you have to do is just pass this to the `` component. - -```jsx title="App.tsx" copy +```tsx title="App.tsx" copy import { GTProvider } from 'gt-react-native'; -import config from './gt.config.json'; +import AppContent from './AppContent'; export default function App() { return ( - {/* // [!code highlight] */} - {/* Your app content */} + }> {/* // [!code highlight] */} + ); } ``` -### Custom translation loader +### Pinning a locale -You can use the `loadTranslations` prop to load translations from a custom source. -This is useful when you need to load translations from a different source, such as a custom API. +Pass the `locale` prop to render the app in a specific locale, ignoring the user's stored selection and device settings: -```jsx title="App.tsx" copy +```tsx title="App.tsx" copy import { GTProvider } from 'gt-react-native'; -import { loadTranslations } from './loadTranslations'; export default function App() { return ( - {/* // [!code highlight] */} - {/* Your app content */} + {/* // [!code highlight] */} + {/* Always renders in French */} ); } ``` -### Render settings - -Render settings controls the loading behavior for translations. -There are two fields: `timeout` and `method`. - -- `timeout` is the number of milliseconds to wait for a translation to load before showing a fallback (default: `8000ms`). -- `method` is the method to use to load translations (`"skeleton"`, `"replace"`, or `"default"`). - -```jsx title="App.tsx" copy - - {/* Your app content */} - -``` - -Each render setting dictates different loading behavior: -`"skeleton"` will return `null` until the translations are loaded. -`"replace"` will return the fallback content until the translations are loaded. -`"default"` will return `null` until the translations are loaded, unless the fallback locale has the same language as the current locale (i.e., `en-US` and `en-GB`). -In this case, it will return the fallback content immediately until the translations are loaded. - --- ## Notes -- The `` must wrap all [`` components](/docs/react-native/api/components/t) and other translation-related functions. Learn more [here](/docs/react-native/api/components/gtprovider). +* Call `initializeGT()` in your entry file before registering your app. `` reads all configuration — locales, API keys, and translation loaders — from there and takes no configuration props. +* The `` must wrap all [`` components](/docs/react-native/api/components/t) and translation hooks. +* Unlike the `gt-react` and `gt-next` providers, `` loads translations asynchronously and renders `fallback` until they are ready. +* The `fallback` renders inside the GT context with an empty translation set, so translation components inside it render source-language content. ## Next steps -- Learn more about the [`` component](/docs/react-native/guides/t) for translating text and components. +- [React Native Quickstart](/docs/react-native/tutorials/quickstart) - Set up `initializeGT()` and `` from scratch +- [`` component](/docs/react-native/guides/t) - Translate text and components +- [Dictionaries guide](/docs/react-native/guides/dictionaries) - Use `useTranslations` with dictionaries diff --git a/docs/en-US/react-native/api/helpers/get-locale-from-native-store.mdx b/docs/en-US/react-native/api/helpers/get-locale-from-native-store.mdx index b82b8a73..f1d91b46 100644 --- a/docs/en-US/react-native/api/helpers/get-locale-from-native-store.mdx +++ b/docs/en-US/react-native/api/helpers/get-locale-from-native-store.mdx @@ -16,7 +16,7 @@ const locale = getLocaleFromNativeStore(key?); | Parameter | Type | Description | |-----------|------|-------------| -| `key` | `string?` | The storage key to read from. Defaults to `'generaltranslation.locale'`. If your [``](/docs/react-native/api/components/gtprovider) uses a custom `localeCookieName`, pass that same value here. | +| `key` | `string?` | The storage key to read from. Defaults to the `localeCookieName` configured through `initializeGT()`, which is `'generaltranslation.locale'` unless customized. | ### Returns @@ -32,7 +32,7 @@ import { getLocaleFromNativeStore } from 'gt-react-native'; const locale = getLocaleFromNativeStore(); ``` -If your `GTProvider` uses a custom `localeCookieName`, pass the same key: +If you set a custom `localeCookieName` in `initializeGT()`, the default key already uses it. Pass a key only to read from a different storage entry: ```jsx copy const locale = getLocaleFromNativeStore('my-custom-key'); diff --git a/docs/en-US/react-native/api/types/dictionary-translation-options.mdx b/docs/en-US/react-native/api/types/dictionary-translation-options.mdx index a28f7b3a..2c289510 100644 --- a/docs/en-US/react-native/api/types/dictionary-translation-options.mdx +++ b/docs/en-US/react-native/api/types/dictionary-translation-options.mdx @@ -1,5 +1,5 @@ --- -title: DictionaryTranslationOptions -description: API reference for the DictionaryTranslationOptions type +title: TranslationVariables +description: API reference for the TranslationVariables type --- {/* AUTO-GENERATED: Do not edit directly. Edit the template in content/docs-templates/ instead. */} diff --git a/docs/en-US/react-native/api/types/inline-translation-options.mdx b/docs/en-US/react-native/api/types/inline-translation-options.mdx index 19ccd2cc..15c42e3d 100644 --- a/docs/en-US/react-native/api/types/inline-translation-options.mdx +++ b/docs/en-US/react-native/api/types/inline-translation-options.mdx @@ -1,5 +1,5 @@ --- -title: InlineTranslationOptions -description: API reference for the InlineTranslationOptions type +title: GTTranslationOptions +description: API reference for the GTTranslationOptions type --- {/* AUTO-GENERATED: Do not edit directly. Edit the template in content/docs-templates/ instead. */} diff --git a/docs/en-US/react-native/faqs.mdx b/docs/en-US/react-native/faqs.mdx index 09b63ed7..b2cc2059 100644 --- a/docs/en-US/react-native/faqs.mdx +++ b/docs/en-US/react-native/faqs.mdx @@ -5,7 +5,7 @@ description: Frequently asked questions about gt-react-native ### What happens if there are missing translations in production? -If a translation for some content is missing in production, gt-react-native automatically falls back to the original source text. Your app will still render correctly — users will just see the default language for that piece of content. +If a translation for some content is missing in production, `gt-react-native` automatically falls back to the original source text. Your app will still render correctly — users will just see the default language for that piece of content. ### Why do I have to install the CLI tool? diff --git a/docs/en-US/react-native/tutorials/mini-shop.mdx b/docs/en-US/react-native/tutorials/mini-shop.mdx index 4ec42f69..a631e6dd 100644 --- a/docs/en-US/react-native/tutorials/mini-shop.mdx +++ b/docs/en-US/react-native/tutorials/mini-shop.mdx @@ -19,7 +19,8 @@ What you'll build Links used in this tutorial - Provider: [``](/docs/react-native/api/components/gtprovider) -- Components: [``](/docs/react-native/api/components/t), [``](/docs/react-native/api/components/var), [``](/docs/react-native/api/components/num), [``](/docs/react-native/api/components/currency), [``](/docs/react-native/api/components/datetime), [``](/docs/react-native/api/components/branch), [``](/docs/react-native/api/components/plural), [``](/docs/react-native/api/components/locale-selector) +- Components: [``](/docs/react-native/api/components/t), [``](/docs/react-native/api/components/var), [``](/docs/react-native/api/components/num), [``](/docs/react-native/api/components/currency), [``](/docs/react-native/api/components/datetime), [``](/docs/react-native/api/components/branch), [``](/docs/react-native/api/components/plural) +- Hooks: [`useLocaleSelector`](/docs/react-native/api/helpers/use-locale-selector) - Strings and Shared Strings: [`useGT`](/docs/react-native/api/strings/use-gt), [`msg`](/docs/react-native/api/strings/msg), [`useMessages`](/docs/react-native/api/strings/use-messages) - Guides: [Variables](/docs/react-native/guides/variables), [Branching](/docs/react-native/guides/branches), [Strings](/docs/react-native/guides/strings), [Local Translation Storage](/docs/react-native/guides/local-tx), [Changing Languages](/docs/react-native/guides/languages) @@ -71,7 +72,22 @@ Install packages and wrap your app with the provider. Then add the files in the sections below (e.g., `App.tsx`, `components/*`, `data.ts`, `nav.ts`). -Create a minimal provider setup. +Initialize the library in your entry file with `initializeGT`, then wrap your app with the provider. + +```ts title="index.ts" copy +import { registerRootComponent } from 'expo'; +import { initializeGT } from 'gt-react-native'; +import App from './App'; + +initializeGT({ + defaultLocale: 'en', + locales: ['es', 'fr'], + projectId: process.env.EXPO_PUBLIC_GT_PROJECT_ID, + devApiKey: process.env.EXPO_PUBLIC_GT_API_KEY, +}); + +registerRootComponent(App); +``` ```tsx title="App.tsx" copy import { GTProvider } from 'gt-react-native'; @@ -79,7 +95,7 @@ import Shop from './Shop'; export default function App() { return ( - + ); @@ -160,7 +176,7 @@ export const products: Product[] = [ ## Shared navigation labels with msg and useMessages -Use [`msg`](/docs/react-native/api/strings/msg) to mark shared strings in config, then decode them via [`useMessages`](/docs/react-native/api/strings/use-messages) at render time. +Use [`msg`](/docs/react-native/api/strings/msg) to mark shared strings in config, then decode them via [`useMessages`](/docs/react-native/api/strings/use-messages) at render time. Build the language switcher with the [`useLocaleSelector`](/docs/react-native/api/helpers/use-locale-selector) hook, which returns the available locales, the current locale, and a setter. ```tsx title="nav.ts" copy import { msg } from 'gt-react-native'; @@ -173,13 +189,13 @@ export const navItems = [ ``` ```tsx title="components/Header.tsx" copy -import { View, Text, StyleSheet } from 'react-native'; -import { LocaleSelector, T } from 'gt-react-native'; -import { useMessages } from 'gt-react-native'; +import { View, Text, Pressable, StyleSheet } from 'react-native'; +import { T, useLocaleSelector, useMessages } from 'gt-react-native'; import { navItems } from '../nav'; export default function Header() { const m = useMessages(); + const { locales, locale, setLocale } = useLocaleSelector(); return ( Mini Shop @@ -190,7 +206,15 @@ export default function Header() { ))} - + + {locales.map((l) => ( + setLocale(l)}> + + {l} + + + ))} + ); } @@ -216,6 +240,10 @@ const styles = StyleSheet.create({ fontSize: 14, color: '#555', }, + activeLocale: { + fontWeight: 'bold', + color: '#111', + }, }); ``` @@ -503,13 +531,17 @@ const styles = StyleSheet.create({ ## Run locally -Start the Expo dev server: +Build and run a development build: ```bash -npx expo start +npx expo run:ios +# or +npx expo run:android ``` -Then open in the Expo Go app on your phone, or press `i` for iOS simulator / `a` for Android emulator. + + **Note:** Expo Go does not work with `gt-react-native` because it includes a native module. Use a [development build](https://docs.expo.dev/develop/development-builds/introduction/) instead. + --- @@ -518,7 +550,7 @@ Then open in the Expo Go app on your phone, or press `i` for iOS simulator / `a` - Expressing conditional content with [``](/docs/react-native/api/components/branch) and quantities with [``](/docs/react-native/api/components/plural) - Translating attributes with [`useGT`](/docs/react-native/api/strings/use-gt) - Sharing navigation/config strings using [`msg`](/docs/react-native/api/strings/msg) and decoding them with [`useMessages`](/docs/react-native/api/strings/use-messages) -- Switching languages with [``](/docs/react-native/api/components/locale-selector) +- Switching languages with [`useLocaleSelector`](/docs/react-native/api/helpers/use-locale-selector) ## Next steps - Explore: [Variables Guide](/docs/react-native/guides/variables), [Branching Guide](/docs/react-native/guides/branches), [Strings Guide](/docs/react-native/guides/strings), [Changing Languages](/docs/react-native/guides/languages) diff --git a/docs/en-US/react-native/tutorials/quickstart-expo.mdx b/docs/en-US/react-native/tutorials/quickstart-expo.mdx index c65b0001..9d78c1af 100644 --- a/docs/en-US/react-native/tutorials/quickstart-expo.mdx +++ b/docs/en-US/react-native/tutorials/quickstart-expo.mdx @@ -83,10 +83,11 @@ Create a **`gt.config.json`** file in your project root. This tells the library React Native's JavaScript runtime doesn't include the `Intl` APIs that `gt-react-native` needs. The easiest fix is the included Babel plugin. -Add it to your Babel config: +Add it to your Babel config, pointing `entryPointFilePath` to the custom entry file you'll create in Step 5: ```js title="babel.config.js" -const gtPlugin = require('gt-react-native/plugin'); +const path = require('path'); +const { plugin: gtPlugin } = require('gt-react-native/plugin'); const gtConfig = require('./gt.config.json'); module.exports = function (api) { @@ -98,7 +99,7 @@ module.exports = function (api) { gtPlugin, { locales: [gtConfig.defaultLocale, ...gtConfig.locales], - entryPointFilePath: require.resolve('expo-router/entry'), + entryPointFilePath: path.resolve(__dirname, 'index.ts'), }, ], ], @@ -112,7 +113,7 @@ module.exports = function (api) { See [FormatJS's polyfill documentation](https://formatjs.github.io/docs/polyfills) for the full list. At minimum you need: - ```tsx title="index.js" + ```tsx title="index.ts" import '@formatjs/intl-getcanonicallocales/polyfill'; import '@formatjs/intl-locale/polyfill'; import '@formatjs/intl-pluralrules/polyfill-force'; @@ -152,31 +153,51 @@ These files are generated by the CLI when you run `npx gt translate`. --- -## Step 5: Add the GTProvider to your layout +## Step 5: Initialize GT and add the provider -The **`GTProvider`** component gives your entire app access to translations. Add it to your root layout: +Configure the library with **`initializeGT`** before Expo Router loads. Create a custom entry file in your project root: + +```ts title="index.ts" +import { initializeGT } from 'gt-react-native'; +import gtConfig from './gt.config.json'; +import { loadTranslations } from './loadTranslations'; + +initializeGT({ + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, + loadTranslations, + projectId: process.env.EXPO_PUBLIC_GT_PROJECT_ID, + devApiKey: process.env.EXPO_PUBLIC_GT_DEV_API_KEY, +}); + +// Load the Expo Router entry point after GT is initialized +require('expo-router/entry'); +``` + +Point the `main` field in your `package.json` at the new entry file: + +```json title="package.json" +{ + "main": "index.ts" +} +``` + +Then wrap your root layout with the **`GTProvider`** component. It reads its configuration from `initializeGT` and takes no config props: ```tsx title="app/_layout.tsx" import { Slot } from 'expo-router'; import { GTProvider } from 'gt-react-native'; -import gtConfig from '../gt.config.json'; -import { loadTranslations } from '../loadTranslations'; export default function RootLayout() { return ( - + ); } ``` -`GTProvider` manages locale state and makes translations available to all child components. The `devApiKey` prop enables on-demand translation during development. +`GTProvider` manages locale state and makes translations available to all child components. The `devApiKey` option enables on-demand translation during development. --- @@ -265,7 +286,7 @@ npx gt auth Yes. Without API keys, `gt-react-native` works as a standard i18n library. You won't get on-demand translation in development, but you can still: - Provide your own translation files manually - - Use all components (``, ``, `LocaleSelector`, etc.) + - Use all components (``, ``, ``, etc.) - Run `npx gt generate` to create translation file templates, then translate them yourself @@ -382,13 +403,13 @@ That's it — your app is now multilingual. 🎉 This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. - Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `context` prop to help: + Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` prop to help: ```jsx - Apple + Apple ``` - Both `` and `useGT()` support the `context` option. + Both `` and `useGT()` support the `$context` option. diff --git a/docs/en-US/react-native/tutorials/quickstart.mdx b/docs/en-US/react-native/tutorials/quickstart.mdx index 07c048ac..e65d635f 100644 --- a/docs/en-US/react-native/tutorials/quickstart.mdx +++ b/docs/en-US/react-native/tutorials/quickstart.mdx @@ -87,7 +87,7 @@ Add it to your Babel config, pointing `entryPointFilePath` to your app's entry f ```js title="babel.config.js" const path = require('path'); -const gtPlugin = require('gt-react-native/plugin'); +const { plugin: gtPlugin } = require('gt-react-native/plugin'); const gtConfig = require('./gt.config.json'); module.exports = { @@ -97,7 +97,7 @@ module.exports = { gtPlugin, { locales: [gtConfig.defaultLocale, ...gtConfig.locales], - entryPointFilePath: path.resolve(__dirname, 'App.tsx'), + entryPointFilePath: path.resolve(__dirname, 'index.js'), }, ], ], @@ -150,30 +150,44 @@ These files are generated by the CLI when you run `npx gt translate`. --- -## Step 5: Add the GTProvider to your app +## Step 5: Initialize GT and add the provider -The **`GTProvider`** component gives your entire app access to translations. Wrap your app at the root level: +Configure the library with **`initializeGT`** in your entry file, before the app is registered: -```tsx title="App.tsx" -import { GTProvider } from 'gt-react-native'; +```js title="index.js" +import { AppRegistry } from 'react-native'; +import { initializeGT } from 'gt-react-native'; +import App from './App'; +import { name as appName } from './app.json'; import gtConfig from './gt.config.json'; import { loadTranslations } from './loadTranslations'; +initializeGT({ + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, + loadTranslations, + projectId: process.env.GT_PROJECT_ID, + devApiKey: process.env.GT_API_KEY, +}); + +AppRegistry.registerComponent(appName, () => App); +``` + +Then wrap your app at the root level with the **`GTProvider`** component. It reads its configuration from `initializeGT` and takes no config props: + +```tsx title="App.tsx" +import { GTProvider } from 'gt-react-native'; + export default function App() { return ( - + {/* Your app content */} ); } ``` -`GTProvider` manages locale state and makes translations available to all child components. The `devApiKey` prop enables on-demand translation during development. +`GTProvider` manages locale state and makes translations available to all child components. The `devApiKey` option enables on-demand translation during development. --- @@ -262,7 +276,7 @@ npx gt auth Yes. Without API keys, `gt-react-native` works as a standard i18n library. You won't get on-demand translation in development, but you can still: - Provide your own translation files manually - - Use all components (``, ``, `LocaleSelector`, etc.) + - Use all components (``, ``, ``, etc.) - Run `npx gt generate` to create translation file templates, then translate them yourself @@ -360,13 +374,13 @@ That's it — your app is now multilingual. 🎉 This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. - Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `context` prop to help: + Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` prop to help: ```jsx - Apple + Apple ``` - Both `` and `useGT()` support the `context` option. + Both `` and `useGT()` support the `$context` option. diff --git a/docs/en-US/react/api/components/gtprovider.mdx b/docs/en-US/react/api/components/gtprovider.mdx index 65c8d604..3c447eb7 100644 --- a/docs/en-US/react/api/components/gtprovider.mdx +++ b/docs/en-US/react/api/components/gtprovider.mdx @@ -5,14 +5,19 @@ description: API reference for the GTProvider component ## Overview -The `` component provides General Translation (GT) context to its children, enabling them to access translated content. -It is required for any client-side translations on your application. +The `` component provides General Translation (GT) context to its children in server-rendered React apps. +It receives the current `locale` and a `translations` snapshot, and renders synchronously — there is no loading state. + +App-wide configuration does not live on the provider. +Configure `gt-react` once at startup with `initializeGT()` (locales, credentials, translation loaders); `` only carries per-request state. ### When to use -- Wrap your entire application in `` to enable translations on the client. +- **Server-rendered apps**: call `initializeGT()` at startup, load a snapshot with `getTranslationsSnapshot(locale)` on the server, and pass it to `` at the root of your component tree. + +- **Single-page apps**: initialize with `initializeGTSPA()` instead. You don't need a `` — components and hooks read from the global GT state. -- The `` component is used for both [inline ``](/docs/react/guides/t) and [dictionaries](/docs/react/guides/dictionaries). +--- ## Reference @@ -20,79 +25,26 @@ It is required for any client-side translations on your application. >', + optional: false, }, - 'loadTranslations?': { - type: '(locale: string) => Promise>', + 'children?': { + type: 'ReactNode', optional: true, }, - 'loadDictionary?': { - type: '(locale: string) => Promise>', + 'dictionaries?': { + type: 'Record', optional: true, }, 'region?': { type: 'string', optional: true, }, - 'fallback?': { - type: 'ReactNode', - optional: true, - }, - 'customMapping?': { - type: 'CustomMapping', - optional: true, - }, 'enableI18n?': { type: 'boolean', optional: true, @@ -103,143 +55,102 @@ It is required for any client-side translations on your application. ### Description -| Prop | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `children` | Any component or the parents of any component that needs to translate or access translation information on the client side. These should include any components using ``, `useGT`, or other translation utilities. | -| `projectId?` | The project ID required for General Translation cloud services. | -| `dictionary?` | The translation dictionary for the project. | -| `locales?` | The list of approved locales for the project. | -| `defaultLocale?` | The default locale to use if no other locale is found. | -| `locale?` | The current locale, if already set. | -| `cacheUrl?` | The URL of the cache service for fetching translations. | -| `runtimeUrl?` | The URL of the runtime service for fetching translations. | -| `renderSettings?` | The settings for rendering translations. | -| `_versionId?` | The version ID for fetching translations. | -| `devApiKey?` | The API key for development environments. | -| `config?` | A configuration object (typically imported from `gt.config.json`) containing `projectId`, `locales`, `defaultLocale`, and other settings. An alternative to passing these as individual props. | -| `loadTranslations?` | An async function that takes a locale string and returns the translations object for that locale. Used to load pre-generated translation files at runtime. See the [quickstart](/docs/react) for usage. | -| `loadDictionary?` | An async function that takes a locale string and returns the dictionary translations for that locale. | -| `region?` | The user's region code (e.g., `US`, `GB`). Used for region-specific formatting. | -| `fallback?` | Custom fallback content to display while translations are loading. | -| `customMapping?` | A mapping of custom component names to their React components, used when rendering translated JSX. | -| `enableI18n?` | Whether to enable i18n features. Defaults to `true`. | +| Prop | Description | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `locale` | The locale to render, e.g. `'fr'`. Typically resolved on the server from the request (cookie or `Accept-Language` header). | +| `translations` | The translations snapshot for the current locale, e.g. the result of `getTranslationsSnapshot(locale)` fetched in a route loader or server handler. | +| `children?` | The subtree that needs access to translations. This should include any components using ``, `useGT`, or other translation utilities. | +| `dictionaries?` | A per-locale dictionary snapshot for [`useTranslations`](/docs/react/api/dictionary/use-translations). | +| `region?` | The user's region code (e.g., `US`, `GB`). Used for region-specific formatting. | +| `enableI18n?` | Whether to enable i18n features. Defaults to `true`. | ### Returns -`React.JSX.Element|undefined` containing the children that were passed to this component. +`React.JSX.Element` containing the children that were passed to this component. -## Examples +--- -### Basic usage - -Wrap your application in `` to add translation to your app. -Don't forget to add a [list of supported locales](/docs/platform/supported-locales) to enable translation. - -```jsx title="index.js" copy -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import "./index.css"; -import App from "./App.tsx"; -import { GTProvider } from "gt-react"; - -createRoot(document.getElementById("root")!).render( - - // Enable Spanish and French // [!code highlight] - - // [!code highlight] - -); -``` +## Examples -### Dictionaries +### Configure GT at startup -You can also pass a dictionary to the `` component and then access it with the [`useTranslations`](/docs/react/api/dictionary/use-translations) hook. +App-wide configuration lives in `initializeGT()`, not on the provider. +Call it once at module scope; the configuration is set once and immutable for the lifetime of the app. -```jsx title="index.js" copy -import dictionary from "./dictionary.js"; +```ts title="src/gt.ts" copy +import { initializeGT } from 'gt-react'; +import gtConfig from '../gt.config.json'; -createRoot(document.getElementById("root")!).render( - - // [!code highlight] - - - -); +initializeGT({ + ...gtConfig, // defaultLocale, locales, projectId, ... + loadTranslations: async (locale: string) => + (await import(`./_gt/${locale}.json`)).default, +}); ``` -For more information on using dictionaries, check out this [guide](/docs/react/guides/dictionaries). +`initializeGT()` accepts your `gt.config.json` fields (`defaultLocale`, `locales`, `customMapping`, `projectId`, `devApiKey`, `apiKey`, `cacheUrl`, `runtimeUrl`) plus cache options (`loadTranslations`, `loadDictionary`, `dictionary`, `cacheExpiryTime`) and custom cookie names (`localeCookieName`, `regionCookieName`, `enableI18nCookieName`). -### Adding configuration +### Server-rendered apps -If you're not a fan of passing props directly to the `` component, you can create a configuration file and pass it to the component. -It also directly integrates with the [`gt translate` command](/docs/cli/translate), so you don't have to specify things like locales manually as a parameter. +Fetch a translations snapshot on the server and pass it to `` along with the resolved locale. +The provider renders synchronously from the snapshot. -```json title="gt.config.json" copy -{ - "projectId": "your-project-id", - "locales": ["es", "fr"], - "defaultLocale": "en-US", - "_versionId": "translation-version-id" // allows for rolling back to previous translations (autogenerated by the CLI) -} -``` - -All you have to do is just pass this to the `` component. +```tsx title="src/root.tsx" copy +import { GTProvider, getTranslationsSnapshot } from 'gt-react'; +import './gt'; // runs initializeGT() -```jsx title="index.js" copy -import config from "../gt.config.json"; +// In your route loader (exact API depends on your framework) +export async function loader({ locale }: { locale: string }) { + return { + locale, + translations: await getTranslationsSnapshot(locale), // [!code highlight] + }; +} -createRoot(document.getElementById("root")!).render( - - // [!code highlight] - +export default function Root({ locale, translations, children }) { + return ( + // [!code highlight] + {children} - -); + ); +} ``` -### Custom translation loader - -You can use the `loadTranslations` prop to load translations from a custom source. -This is useful when you need to load translations from a different source, such as a custom API. - -```jsx title="index.js" copy -import loadTranslations from "./loadTranslations"; - -createRoot(document.getElementById("root")!).render( - - // [!code highlight] - - - -); -``` +### Single-page apps -### Render settings +SPAs don't use ``. +Call `initializeGTSPA()` in your entry point instead — it resolves once the initial translations are loaded, so render your app after it completes. -Render settings controls the loading behavior for translations. -There are two fields: `timeout` and `method`. +```tsx title="src/main.tsx" copy +import { createRoot } from 'react-dom/client'; +import { initializeGTSPA } from 'gt-react'; +import gtConfig from '../gt.config.json'; +import App from './App'; -- `timeout` is the number of milliseconds to wait for a translation to load before showing a fallback (default: `8000ms`). -- `method` is the method to use to load translations (`"skeleton"`, `"replace"`, or `"default"`). +await initializeGTSPA({ + ...gtConfig, + loadTranslations: async (locale: string) => + (await import(`./_gt/${locale}.json`)).default, +}); -```jsx title="index.js" copy - - - +createRoot(document.getElementById('root')!).render(); ``` -Each render setting dictates different loading behavior: -`"skeleton"` will return `null` until the translations are loaded. -`"replace"` will return the fallback content until the translations are loaded. -`"default"` will return `null` until the translations are loaded, unless the fallback locale has the same language as the current locale (i.e., `en-US` and `en-GB`). -In this case, it will return the fallback content immediately until the translations are loaded. + + **Vite credentials:** During initialization, `gt-react` automatically reads `VITE_GT_PROJECT_ID` and `VITE_GT_DEV_API_KEY` from your environment. The dev API key is only read in development. + --- ## Notes -- The `` must wrap all [`` components](/docs/react/api/components/t) and other translation-related functions. Learn more [here](/docs/react/api/components/gtprovider). +* Configuration passed to `initializeGT()` or `initializeGTSPA()` is read once at startup and is immutable for the lifetime of the app. +* `` renders synchronously from the `translations` snapshot — there is no loading state or fallback content. +* In server-rendered apps, the `` must wrap all [`` components](/docs/react/api/components/t) and translation hooks. +* In SPAs initialized with `initializeGTSPA()`, components and hooks work without a ``. ## Next steps - Learn more about the [`` component](/docs/react/guides/t) for translating text and components. +- Learn how to load translations with [`loadTranslations`](/docs/react/api/config/load-translations). +- See the [React Quickstart](/docs/react) for a full SPA setup walkthrough. diff --git a/docs/en-US/react/api/strings/t-function.mdx b/docs/en-US/react/api/strings/t-function.mdx index b182070c..1b16a298 100644 --- a/docs/en-US/react/api/strings/t-function.mdx +++ b/docs/en-US/react/api/strings/t-function.mdx @@ -5,85 +5,76 @@ description: API reference for the t() synchronous string translation function ## Overview -The `t` function is a synchronous, module-level string translation function for client-side React applications. +The `t()` function synchronously translates a string for the current locale. -```jsx -import { t } from 'gt-react/browser'; +```tsx +import { t } from 'gt-react'; const greeting = t('Hello, world!'); ``` `t` can also be used as a tagged template literal: -```jsx -import { t } from 'gt-react/browser'; +```tsx +import { t } from 'gt-react'; const greeting = t`Hello, ${name}!`; ``` -Unlike `useGT` (which requires React context) or `msg` (which encodes strings for later resolution), `t()` returns the translated string directly. It can be called anywhere in browser code — including at module scope, outside of React components. - - -**Experimental:** `t()` is an experimental feature. It is designed for client-side only React applications and does not yet integrate with React context (e.g., ``, `useGT`). If called on the server, it logs a warning and returns the source string. - +Unlike `useGT` (a React hook) or `msg` (which encodes strings for later resolution), `t()` returns the translated string directly and does not require React context. +In single-page apps it can be called anywhere — including at module scope, outside of React components. --- -## Setup +## Reference -`t()` depends on `bootstrap()` to load translations before your app renders. You need to change the entry point of your app to run `bootstrap()` first. +### Parameters -Typically the entry point is `main.tsx`. You'll create a new file (e.g., `bootstrap.tsx`) and point your `index.html` to it instead. +| Name | Type | Description | +|------------|------------------------|---------------------------------------------------------------------------------------------------| +| `message` | `string` | The string to translate. | +| `options?` | `GTTranslationOptions` | Optional. Interpolation variables, plus metadata options such as `$context`, `$id`, and `$locale`. | -### 1. Create the bootstrap entry point +### Returns -```tsx -// bootstrap.tsx -import gtConfig from '../gt.config.json'; -import { bootstrap } from 'gt-react/browser'; +`string` — The translated string for the current locale, or the source string (with variables interpolated) if no translation is available. -async function loadTranslations(locale: string) { - return (await import(`./_gt/${locale}.json`)).default; -} +### Throws -await bootstrap({ - ...gtConfig, - loadTranslations, -}); +In server-rendered apps, calling `t()` at module level throws an error in development. +In production, it logs the error and falls back to the default locale value. +Call `t()` in request-time scope instead, or register module-level strings with [`msg`](/docs/react/api/strings/msg). -await import('./main.tsx'); -``` +--- -By default, `bootstrap()` automatically updates the `` element's `lang` and `dir` attributes to match the current locale. -You can configure this behavior with `htmlTagOptions`: +## Examples -```tsx -await bootstrap({ - ...gtConfig, - loadTranslations, - htmlTagOptions: { - updateHtmlLangTag: true, // default: true - updateHtmlDirTag: false, // default: true - }, -}); -``` +### Single-page apps -You can also manually update these attributes at any time using the `updateHtmlTagLang` and `updateHtmlTagDir` helper functions from `gt-react/browser`. +`t()` resolves from the translations loaded during initialization. +`initializeGTSPA()` resolves once the initial translations are loaded, so await it in your entry point before rendering: -### 2. Update your `index.html` +```tsx title="src/main.tsx" copy +import { createRoot } from 'react-dom/client'; +import { initializeGTSPA } from 'gt-react'; +import gtConfig from '../gt.config.json'; -In your `index.html`, update the module entry point to point to your new bootstrap file instead of `main.tsx`: +await initializeGTSPA({ + ...gtConfig, + loadTranslations: async (locale: string) => + (await import(`./_gt/${locale}.json`)).default, +}); -```text -src="/src/bootstrap.tsx" +const { default: App } = await import('./App'); +createRoot(document.getElementById('root')!).render(); ``` -### 3. Use `t()` anywhere +Then call `t()` anywhere — even at module scope: -```tsx -import { t } from 'gt-react/browser'; +```tsx title="src/nav.tsx" copy +import { t } from 'gt-react'; -// Module-level — runs at import time +// Module level — runs at import time const navItems = [ { label: t('Home'), path: '/' }, { label: t('About'), path: '/about' }, @@ -101,77 +92,35 @@ export default function Nav() { } ``` - -**Standalone setup:** `t()` does not currently integrate with the rest of the `gt-react` system (e.g., ``, `useGT`). You need to use the bootstrap setup described above. - - ---- - -## Tagged template literal - -`t` can be used as a tagged template literal for a more natural syntax: - -```tsx -import { t } from 'gt-react/browser'; - -// These are equivalent: -t('Hello, {name}!', { name: 'Alice' }); -t`Hello, ${name}!`; -``` - -The tagged template form eliminates the need for ICU-style placeholders and options objects — variables are interpolated directly from the template expression. - -### Global registration - -Instead of importing `t` in every file, you can register it globally: +By default, initialization also updates the `` element's `lang` and `dir` attributes to match the current locale. +Configure this with the `htmlTagOptions` field of `initializeGTSPA()`: ```tsx -// In your app's entry point -import "gt-react/macros"; -``` - -This sets `globalThis.t`, making the tagged template available everywhere without an explicit import: - -```tsx -// No import needed -const labels = { - save: t`Save`, - cancel: t`Cancel`, -}; +await initializeGTSPA({ + ...gtConfig, + loadTranslations, + htmlTagOptions: { + updateHtmlLangTag: true, // default: true + updateHtmlDirTag: false, // default: true + }, +}); ``` ---- - -## Reference - -### Parameters - -| Name | Type | Description | -|------------|----------|-----------------------------------------------------------------------------| -| `message` | `string` | The string to translate. | -| `options?` | `object` | Optional. An object containing variable values for interpolation. | - -### Returns - -`string` — The translated string for the current locale, or the source string if no translation is available. - ---- - -## Variables +### Variables -You can pass variables using curly brace syntax: +Pass variables using ICU-style curly brace placeholders: ```tsx -import { t } from 'gt-react/browser'; +import { t } from 'gt-react'; const message = t('Hello, {name}!', { name: 'Alice' }); // → "Hola, Alice!" (in Spanish) ``` -Or use the tagged template form, which handles interpolation automatically: +Or use the tagged template form, which interpolates variables directly from the template expressions: ```tsx -import { t } from 'gt-react/browser'; +import { t } from 'gt-react'; const message = t`Hello, ${name}!`; // → "Hola, Alice!" (in Spanish, when name = 'Alice') @@ -179,66 +128,61 @@ const message = t`Hello, ${name}!`; Variable values are not translated — only the surrounding string template is. ---- - -## Behavior - -### How it works +### Translation context -`bootstrap()` asynchronously loads all translations for the current locale before the app's modules are imported. Once loaded, `t()` reads from the translation data synchronously with no overhead. +Use `$context` to disambiguate content for the translation model: -Because translations are resolved at module load time: - -- **Switching locales requires a full page reload.** The browser must re-execute all modules to pick up the new translations. -- **This only works in client-side apps.** Module-level code re-executes when loaded in the browser, which is what makes this pattern possible. +```tsx +import { t } from 'gt-react'; -### Server-side behavior +const label = t('Apple', { $context: 'the technology company' }); +``` -If `t()` is called in a server environment (where `window` is undefined), it logs a warning and returns the original source string. For server-side translation, use React context-based hooks like `useGT`. +### Global registration ---- +Instead of importing `t` in every file, you can register the tagged template form globally: -## Example +```tsx title="src/main.tsx" +import 'gt-react/macros'; +``` -### Constants file +This sets `globalThis.t`, making the tagged template available everywhere without an explicit import: ```tsx -// constants.ts -import { t } from 'gt-react/browser'; - -export const ERROR_MESSAGES = { - notFound: t('Page not found'), - unauthorized: t('You do not have permission to view this page'), - serverError: t('Something went wrong. Please try again later.'), +// No import needed +const labels = { + save: t`Save`, + cancel: t`Cancel`, }; ``` -### Router definitions +### Server-rendered apps + +In server-rendered apps, `t()` must not run at module level — the locale is not known until request time: ```tsx -// routes.ts -import { t } from 'gt-react/browser'; +import { t } from 'gt-react'; -export const routes = [ - { path: '/', label: t('Home') }, - { path: '/dashboard', label: t('Dashboard') }, - { path: '/settings', label: t('Settings') }, -]; +// ❌ Wrong — module level in a server-rendered app +const title = t('Dashboard'); + +export default function Dashboard() { + // ✅ Correct — request-time scope + return

{t('Dashboard')}

; +} ``` +For module-level strings in server-rendered apps, register them with [`msg`](/docs/react/api/strings/msg) and resolve them with [`useMessages`](/docs/react/api/strings/use-messages). + --- ## Notes -- `t()` is imported from `gt-react/browser`, not from `gt-react` directly. -- Requires `bootstrap()` to be called before any module that uses `t()` is loaded. -- **Experimental.** Does not yet integrate with `` or other `gt-react` context-based features. -- Switching locales requires a full page reload. - -## Dev logs - -- [gt-react@10.12.0](/devlog/gt-react_v10_12_0) — introduction of the `t()` function -- [gt-react@10.13.0](/devlog/gt-react_v10_13_0) — tagged template literal support +* `t()` is imported from `gt-react`. +* In an SPA, await `initializeGTSPA()` before any module that calls `t()` at module scope. +* When a translation is missing, `t()` falls back to the source string with variables interpolated. +* Switching locales reloads the page by default, which re-executes module-level `t()` calls with the new locale. +* The compiler transforms tagged templates (`` t`...` ``) at build time; without the transform, they still resolve at runtime. ## Next steps diff --git a/docs/en-US/react/api/types/dictionary-translation-options.mdx b/docs/en-US/react/api/types/dictionary-translation-options.mdx index a28f7b3a..2c289510 100644 --- a/docs/en-US/react/api/types/dictionary-translation-options.mdx +++ b/docs/en-US/react/api/types/dictionary-translation-options.mdx @@ -1,5 +1,5 @@ --- -title: DictionaryTranslationOptions -description: API reference for the DictionaryTranslationOptions type +title: TranslationVariables +description: API reference for the TranslationVariables type --- {/* AUTO-GENERATED: Do not edit directly. Edit the template in content/docs-templates/ instead. */} diff --git a/docs/en-US/react/api/types/inline-translation-options.mdx b/docs/en-US/react/api/types/inline-translation-options.mdx index 19ccd2cc..15c42e3d 100644 --- a/docs/en-US/react/api/types/inline-translation-options.mdx +++ b/docs/en-US/react/api/types/inline-translation-options.mdx @@ -1,5 +1,5 @@ --- -title: InlineTranslationOptions -description: API reference for the InlineTranslationOptions type +title: GTTranslationOptions +description: API reference for the GTTranslationOptions type --- {/* AUTO-GENERATED: Do not edit directly. Edit the template in content/docs-templates/ instead. */} diff --git a/docs/en-US/react/concepts/compiler.mdx b/docs/en-US/react/concepts/compiler.mdx index c3816583..5c220e63 100644 --- a/docs/en-US/react/concepts/compiler.mdx +++ b/docs/en-US/react/concepts/compiler.mdx @@ -85,3 +85,33 @@ The compiler detects the translatable text and wraps it automatically when you r - **Other GT components** like ``, ``, ``, and `` are also respected - **String attributes** (e.g., `placeholder`, `alt`) are not affected — only JSX children are wrapped - **Non-text content** like numbers and booleans is ignored + +## Legacy import source + +The compiler emits its injected imports (for auto-wrapped JSX and transformed `t` macros) from `gt-react`. If your app is on an older `gt-react` major that exposes these APIs from `gt-react/browser`, enable `legacyGtReactImportSource` (default: `false`) so the injected imports resolve. + +Set it in your `gt.config.json`: + +```json title="gt.config.json" +{ + "files": { + "gt": { + "parsingFlags": { + "legacyGtReactImportSource": true + } + } + } +} +``` + +If you configure the build plugin directly, pass it as a plugin option instead: + +```js title="vite.config.js" +import { vite as gtCompiler } from '@generaltranslation/compiler'; + +export default { + plugins: [gtCompiler({ legacyGtReactImportSource: true })], +}; +``` + +The plugin option takes precedence over the `gt.config.json` flag. diff --git a/docs/en-US/react/faqs.mdx b/docs/en-US/react/faqs.mdx index 1414fb32..c193a661 100644 --- a/docs/en-US/react/faqs.mdx +++ b/docs/en-US/react/faqs.mdx @@ -5,7 +5,9 @@ description: Frequently asked questions about gt-react ### What happens if there are missing translations in production? -If a translation for some content is missing in production, gt-react automatically falls back to the original source text. Your app will still render correctly — users will just see the default language for that piece of content. +If a translation for some content is missing in production, `gt-react` automatically falls back to the original source text. Your app will still render correctly — users will just see the default language for that piece of content. + +The same applies to dictionaries: if a target-locale translation for an entry is missing, `useTranslations` falls back to the source entry. However, if the entry itself is missing from the source dictionary, `useTranslations` throws an error (in both development and production). ### Why do I have to install the CLI tool? diff --git a/docs/en-US/react/index.mdx b/docs/en-US/react/index.mdx index 024fe556..d6a13a09 100644 --- a/docs/en-US/react/index.mdx +++ b/docs/en-US/react/index.mdx @@ -128,47 +128,55 @@ This function loads JSON translation files from your `public/_gt/` directory. Th --- -## Step 4: Add the GTProvider to your app +## Step 4: Initialize the library -The **`GTProvider`** component gives your entire app access to translations. Wrap your app at the root level: +Call **`initializeGTSPA`** in your entry point, before rendering your app. It takes your config and translation loader, determines the user's locale, and loads the translations for it: -```tsx title="src/App.tsx" -import { GTProvider } from 'gt-react'; +```tsx title="src/main.tsx" +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { initializeGTSPA } from 'gt-react'; import gtConfig from '../gt.config.json'; import loadTranslations from './loadTranslations'; - -export default function App() { - return ( - - {/* Your app content */} - - ); -} +import App from './App'; + +// Resolves once the initial translations are loaded +await initializeGTSPA({ + ...gtConfig, + loadTranslations, +}); + +createRoot(document.getElementById('root')!).render( + + + +); ``` -`GTProvider` takes your config and translation loader as props. It manages locale state and makes translations available to all child components. +`initializeGTSPA` runs once at startup — the configuration is immutable for the lifetime of the app. After it resolves, every component and hook in your app can access translations. You don't need to wrap your app in a provider. - CRA restricts imports to files inside `src/`, so `import gtConfig from '../gt.config.json'` will fail. Either copy `gt.config.json` into `src/`, or inline the config directly: + CRA restricts imports to files inside `src/` and may not support top-level `await`, so inline the config and render inside `.then()`: - ```tsx title="src/App.tsx" - import { GTProvider } from 'gt-react'; + ```tsx title="src/index.tsx" + import { StrictMode } from 'react'; + import { createRoot } from 'react-dom/client'; + import { initializeGTSPA } from 'gt-react'; import loadTranslations from './loadTranslations'; - - export default function App() { - return ( - - {/* Your app content */} - + import App from './App'; + + initializeGTSPA({ + defaultLocale: 'en', + locales: ['es', 'fr', 'ja'], + loadTranslations, + }).then(() => { + createRoot(document.getElementById('root')!).render( + + + ); - } + }); ``` @@ -231,14 +239,31 @@ Create a **`.env.local`** file with the correct prefix for your bundler: ```bash title=".env.local" - VITE_GT_API_KEY="your-dev-api-key" VITE_GT_PROJECT_ID="your-project-id" + VITE_GT_DEV_API_KEY="your-dev-api-key" ``` + + `gt-react` reads these automatically during initialization — no extra code needed. The dev API key is only read in development, so it stays out of production bundles. ```bash title=".env.local" - REACT_APP_GT_API_KEY="your-dev-api-key" REACT_APP_GT_PROJECT_ID="your-project-id" + REACT_APP_GT_DEV_API_KEY="your-dev-api-key" + ``` + + CRA environment variables are not read automatically — pass them to `initializeGTSPA`: + + ```tsx title="src/index.tsx" + initializeGTSPA({ + defaultLocale: 'en', + locales: ['es', 'fr', 'ja'], + loadTranslations, + projectId: process.env.REACT_APP_GT_PROJECT_ID, + devApiKey: + process.env.NODE_ENV === 'development' + ? process.env.REACT_APP_GT_DEV_API_KEY + : undefined, + }); ``` @@ -296,7 +321,7 @@ Start your dev server: Open your app and use the language dropdown to switch languages. You should see your content translated. - In development, translations happen on-demand — you may see a brief loading state the first time you switch to a new language. In production, translations are pre-generated and load instantly. + **Note:** In development, translations happen on-demand — content may briefly appear in your source language the first time you switch to a new language, then update once the translation is ready. In production, translations are pre-generated and load instantly. --- @@ -366,13 +391,13 @@ That's it — your app is now multilingual. 🎉 This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. - Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `context` prop to help: + Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` prop to help: ```jsx - Apple + Apple ``` - Both `` and `useGT()` support the `context` option. + Both `` and `useGT()` support the `$context` option. diff --git a/docs/en-US/react/tutorials/mini-shop.mdx b/docs/en-US/react/tutorials/mini-shop.mdx index fc774784..1662098f 100644 --- a/docs/en-US/react/tutorials/mini-shop.mdx +++ b/docs/en-US/react/tutorials/mini-shop.mdx @@ -14,16 +14,15 @@ What you’ll build - Optional: local translation storage for production builds Links used in this tutorial -- Provider: [``](/docs/react/api/components/gtprovider) - Components: [``](/docs/react/api/components/t), [``](/docs/react/api/components/var), [``](/docs/react/api/components/num), [``](/docs/react/api/components/currency), [``](/docs/react/api/components/datetime), [``](/docs/react/api/components/branch), [``](/docs/react/api/components/plural), [``](/docs/react/api/components/locale-selector) - Strings and Shared Strings: [`useGT`](/docs/react/api/strings/use-gt), [`msg`](/docs/react/api/strings/msg), [`useMessages`](/docs/react/api/strings/use-messages) - Guides: [Variables](/docs/react/guides/variables), [Branching](/docs/react/guides/branches), [Strings](/docs/react/guides/strings), [Local Translation Storage](/docs/react/guides/local-tx), [Changing Languages](/docs/react/guides/languages) --- -## Install and wrap your app +## Install and initialize your app -Install packages and wrap your app with the provider. +Install packages and initialize the library in your entry point. @@ -67,19 +66,23 @@ Install packages and wrap your app with the provider. Then add the files in the sections below (e.g., `src/main.tsx`, `src/App.tsx`, `src/components/*`, `src/data.ts`, `src/nav.ts`). -Create a minimal provider setup. +Create a minimal setup. `initializeGTSPA` runs once at startup and resolves when the initial translations are loaded, so await it before rendering. ```tsx title="src/main.tsx" copy import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import { GTProvider } from 'gt-react'; // See: /docs/react/api/components/gtprovider +import { initializeGTSPA } from 'gt-react'; import App from './App'; +// Enable Spanish and French +await initializeGTSPA({ + defaultLocale: 'en', + locales: ['es', 'fr'], +}); + createRoot(document.getElementById('root')!).render( - {/* Enable Spanish and French */} - - + ); ``` @@ -102,14 +105,30 @@ Learn more in [Production vs Development](/docs/react/concepts/environments). ```bash title=".env.local" copy - VITE_GT_API_KEY="your-dev-api-key" VITE_GT_PROJECT_ID="your-project-id" + VITE_GT_DEV_API_KEY="your-dev-api-key" ``` + + `gt-react` reads these automatically during initialization. The dev API key is only read in development. ```bash title=".env.local" copy - REACT_APP_GT_API_KEY="your-dev-api-key" REACT_APP_GT_PROJECT_ID="your-project-id" + REACT_APP_GT_DEV_API_KEY="your-dev-api-key" + ``` + + CRA environment variables are not read automatically — pass them to `initializeGTSPA`: + + ```tsx copy + await initializeGTSPA({ + defaultLocale: 'en', + locales: ['es', 'fr'], + projectId: process.env.REACT_APP_GT_PROJECT_ID, + devApiKey: + process.env.NODE_ENV === 'development' + ? process.env.REACT_APP_GT_DEV_API_KEY + : undefined, + }); ``` diff --git a/docs/en-US/tanstack-start/index.mdx b/docs/en-US/tanstack-start/index.mdx index 1f6da174..43249ab6 100644 --- a/docs/en-US/tanstack-start/index.mdx +++ b/docs/en-US/tanstack-start/index.mdx @@ -79,7 +79,7 @@ export default async function loadTranslations(locale: string) { ### Root route setup -Update `src/routes/__root.tsx` to initialize GT and provide translations: +Update `src/routes/__root.tsx` to initialize GT and provide translations. In the loader, resolve the request locale with `parseLocale()`, then load the matching translations snapshot with `getTranslationsSnapshot(locale)`: ```tsx title="src/routes/__root.tsx" import { @@ -90,8 +90,8 @@ import { import { initializeGT, GTProvider, - getTranslations, - getLocale, + getTranslationsSnapshot, + parseLocale, LocaleSelector, } from 'gt-tanstack-start' import gtConfig from '../../gt.config.json' @@ -111,9 +111,10 @@ export const Route = createRootRoute({ ], }), loader: async () => { + const locale = parseLocale() return { - translations: await getTranslations(), - locale: getLocale(), + locale, + translations: await getTranslationsSnapshot(locale), } }, shellComponent: RootDocument, @@ -127,7 +128,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { - + {children} @@ -138,6 +139,10 @@ function RootDocument({ children }: { children: React.ReactNode }) { } ``` + + **Required props:** `` requires both `locale` and `translations`. The provider has no loading state — translation loading is delegated to the route loader, so TanStack Start's loader and pending mechanics control what renders while translations load. + + ## Usage Wrap content in `` to translate it. Import `` from `gt-react`: @@ -242,12 +247,6 @@ Add the translation step to your build script: } ``` -## Example app - -See the complete working example: [tanstack-start-basic](https://github.com/generaltranslation/gt/tree/main/examples/tanstack-start-basic) - ---- - ## Next steps - Read the [overview](/docs/tanstack-start/introduction) for a deeper look at the API diff --git a/docs/en-US/tanstack-start/introduction.mdx b/docs/en-US/tanstack-start/introduction.mdx index 4891ede8..93efc958 100644 --- a/docs/en-US/tanstack-start/introduction.mdx +++ b/docs/en-US/tanstack-start/introduction.mdx @@ -7,7 +7,7 @@ description: Overview of General Translation's TanStack Start SDK `gt-tanstack-start` is an open-source internationalization (i18n) integration for [TanStack Start](https://tanstack.com/start) applications. -It brings the same developer experience as [`gt-next`](/docs/next) — wrap content in ``, and it gets translated — to the TanStack Start framework. Built on top of [`gt-react`](/docs/react), it adds TanStack Start–specific features like isomorphic locale detection and root loader integration. +It brings the same developer experience as [`gt-next`](/docs/next) — wrap content in ``, and it gets translated — to the TanStack Start framework. Built on top of [`gt-react`](/docs/react), it re-exports the `gt-react` API (components, hooks, and string functions like `msg`) and adds the TanStack Start–specific `parseLocale()` function for isomorphic locale detection. **Experimental:** `gt-tanstack-start` is under active development. APIs may change between minor versions. It is not yet recommended for production use. @@ -47,25 +47,28 @@ initializeGT({ ## Root loader -Use `getTranslations()` and `getLocale()` in your root route's loader to fetch the right translations for the current request: +Use `parseLocale()` and `getTranslationsSnapshot()` in your root route's loader to resolve the locale and fetch the right translations for the current request: ```tsx title="src/routes/__root.tsx" -import { getTranslations, getLocale } from 'gt-tanstack-start' +import { getTranslationsSnapshot, parseLocale } from 'gt-tanstack-start' export const Route = createRootRoute({ loader: async () => { + const locale = parseLocale() return { - translations: await getTranslations(), - locale: getLocale(), + locale, + translations: await getTranslationsSnapshot(locale), } }, // ... }) ``` +`parseLocale()` resolves the request locale isomorphically: on the server, it checks the locale cookie and the `Accept-Language` header, then writes the resolved locale back to the cookie; in the browser, it reads the locale cookie. `getTranslationsSnapshot(locale)` returns a promise of the translations snapshot for that locale, ready to pass to ``. + ## The `` component -The `` provides translation context to all child components. Pass the translations and locale from the loader: +The `` provides translation context to all child components. Pass the locale and translations from the loader — both props are required: ```tsx title="src/routes/__root.tsx" import { GTProvider } from 'gt-tanstack-start' @@ -78,7 +81,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { - + {children} @@ -88,6 +91,8 @@ function RootDocument({ children }: { children: React.ReactNode }) { } ``` +The provider has no loading state of its own. Because translations are loaded in the route loader, TanStack Start's loader and pending mechanics control what renders while translations load. + ## The `` component The [``](/docs/react/api/components/t) component translates JSX content. Wrap any elements and they render in the user's language: @@ -130,5 +135,4 @@ function Nav() { ## Next steps - Set up your project with the [quickstart guide](/docs/tanstack-start) -- Browse the [example app](https://github.com/generaltranslation/gt/tree/main/examples/tanstack-start-basic) - Learn about [variable components](/docs/react/guides/variables) like ``, ``, and `` From 5f491e2920f7c8297ffba35919225e32242c32d4 Mon Sep 17 00:00:00 2001 From: Ernest McCarter Date: Fri, 3 Jul 2026 16:40:29 -0700 Subject: [PATCH 2/3] docs: split React quickstart into SPA and server-rendered guides Setup now differs fundamentally between the two rendering models, so each gets its own quickstart. Also cross-references all quickstarts against the official gt-test-apps (odysseus) and fixes drift found there. - react: new tutorials/quickstart-spa (initializeGTSPA entry-split pattern, compiler plugin step, no provider) and tutorials/quickstart-ssr (initializeGT + getTranslationsSnapshot loader + GTProvider); index.mdx is now a chooser page; nav updated (removes dangling quickstart entry) - tanstack-start: install/import from gt-tanstack-start only, root route uses component + Outlet, explicit initializeGT params, selective SSR section, correct dev port - next: html lang={await getLocale()} in quickstart layout, cache-components auto-detected getLocale/getRegion pattern and fence fixes, ssg anchor that the shipped gt-next warning deep-links to - node: middleware examples use getRequestLocale(req) Co-Authored-By: Claude Fable 5 --- docs/en-US/next/guides/cache-components.mdx | 40 +- docs/en-US/next/guides/ssg.mdx | 6 +- docs/en-US/next/index.mdx | 7 +- docs/en-US/node/api/with-gt.mdx | 6 +- docs/en-US/node/tutorials/quickstart.mdx | 17 +- .../en-US/react/api/components/gtprovider.mdx | 2 +- docs/en-US/react/index.mdx | 420 +---------------- docs/en-US/react/meta.json | 3 +- docs/en-US/react/tutorials/quickstart-spa.mdx | 442 ++++++++++++++++++ docs/en-US/react/tutorials/quickstart-ssr.mdx | 291 ++++++++++++ docs/en-US/tanstack-start/index.mdx | 44 +- docs/en-US/tanstack-start/introduction.mdx | 26 +- 12 files changed, 850 insertions(+), 454 deletions(-) create mode 100644 docs/en-US/react/tutorials/quickstart-spa.mdx create mode 100644 docs/en-US/react/tutorials/quickstart-ssr.mdx diff --git a/docs/en-US/next/guides/cache-components.mdx b/docs/en-US/next/guides/cache-components.mdx index 14e65d48..573e87be 100644 --- a/docs/en-US/next/guides/cache-components.mdx +++ b/docs/en-US/next/guides/cache-components.mdx @@ -21,19 +21,17 @@ Enable cache components in your Next.js config, and define custom `getLocale` an Your `[locale]` segment must be a **root parameter** — the first dynamic segment in your app directory, with no `app/layout.tsx` above it. Your root layout must live inside `app/[locale]/`. -```js title="next.config.js" +```ts title="next.config.ts" +import { withGTConfig } from 'gt-next/config'; + const nextConfig = { cacheComponents: true, }; -export default withGTConfig(nextConfig, { - // Point to your custom request functions - getLocalePath: './getLocale.ts', - getRegionPath: './getRegion.ts', -}); +export default withGTConfig(nextConfig); ``` -Create these files in your project root. They use `next/root-params` instead of `headers()`, which means they work inside `"use cache"` boundaries: +Create `getLocale.ts` and `getRegion.ts` in your project root (or `src/` directory) — `withGTConfig` detects them automatically. They use `next/root-params` instead of `headers()`, which means they work inside `"use cache"` boundaries: ```ts title="getLocale.ts" import { locale } from 'next/root-params'; @@ -49,6 +47,15 @@ export default async function getRegion(): Promise { } ``` +If you keep these files elsewhere, point `withGTConfig` at them with `getLocalePath` and `getRegionPath`: + +```ts title="next.config.ts" +export default withGTConfig(nextConfig, { + getLocalePath: './src/i18n/getLocale.ts', + getRegionPath: './src/i18n/getRegion.ts', +}); +``` + **Do not use `headers()` in your `getLocale` or `getRegion` functions.** Calling `headers()` inside a `"use cache"` boundary causes a build error. Use `next/root-params` as shown above. @@ -73,23 +80,26 @@ If your loader performs dynamic loading, mark it with `"use cache"`. ### Enable middleware - See the full middleware guide [here](/docs/next/guides/middleware). - ```ts - import { createNextMiddleware } from 'gt-next/middleware'; + +Create `proxy.ts` (Next.js 16+) or `middleware.ts` (Next.js 15 and below) in your project root. See the full [middleware guide](/docs/next/guides/middleware). + +```ts title="proxy.ts" +import { createNextMiddleware } from 'gt-next/middleware'; export default createNextMiddleware(); export const config = { -// Match all paths except API routes, static files, and Next.js internals -matcher: ['/((?!api|static|.*\\..*|_next).*)'] + // Match all paths except API routes, static files, and Next.js internals + matcher: ['/((?!api|static|.*\\..*|_next).*)'], }; - ``` - + + ### Add the `locale` parameter to cached components with translatable content When using cached components with translatable content, you must pass the `locale` as a parameter. This ensures each locale gets its own cache entry. ```tsx +import { T } from "gt-next" import { getLocale } from "gt-next/server" async function CachedContent({locale}: {locale: string}) { @@ -108,7 +118,7 @@ export default async function Page() { ## Configuration notes -- When using custom `getLocalePath` and `getRegionPath`, those functions handle locale and region resolution for cached components. +- When custom `getLocale` and `getRegion` functions are configured (auto-detected or via `getLocalePath` and `getRegionPath`), those functions handle locale and region resolution for cached components. - The `next/root-params` API allows reading route parameters like `[locale]` from anywhere in the component tree, including inside `"use cache"` boundaries. The root param value automatically becomes part of the cache key. - The `[locale]` segment must be a root parameter (no `app/layout.tsx` above it). - With `cacheComponents` enabled, `gt-next` delegates caching to Next.js: it forces its own translation cache expiry off (`cacheExpiryTime: 0`). diff --git a/docs/en-US/next/guides/ssg.mdx b/docs/en-US/next/guides/ssg.mdx index 7ab836d7..85115f39 100644 --- a/docs/en-US/next/guides/ssg.mdx +++ b/docs/en-US/next/guides/ssg.mdx @@ -49,9 +49,9 @@ export const config = { }; ``` -### Step 2: Define locale and region detection +### Step 2: Define locale detection [#ssg-custom-get-locale] -Create a `getLocale` and `getRegion` function for locale and region detection during static rendering: +Create a `getLocale` function for locale detection during static rendering: #### Next.js 15.5+ @@ -144,7 +144,7 @@ If your pages aren't being statically generated, ensure that: ``` This error occurs when `getLocale` or `getRegion` files do not exist or are not properly configured. -Double check that [step 2](#step-2-define-locale-and-region-detection) and [step 3](#step-3-disable-getregion) are complete. +Double check that [step 2](#ssg-custom-get-locale) and [step 3](#step-3-disable-getregion) are complete. ### "Export locale doesn't exist in target module" diff --git a/docs/en-US/next/index.mdx b/docs/en-US/next/index.mdx index 2d4b8683..b31b2165 100644 --- a/docs/en-US/next/index.mdx +++ b/docs/en-US/next/index.mdx @@ -117,10 +117,11 @@ The **`GTProvider`** component gives your entire app access to translations. It ```tsx title="app/layout.tsx" import { GTProvider } from 'gt-next'; +import { getLocale } from 'gt-next/server'; -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default async function RootLayout({ children }: { children: React.ReactNode }) { return ( - + {children} @@ -133,6 +134,8 @@ export default function RootLayout({ children }: { children: React.ReactNode }) `GTProvider` is a **server component** — it loads translations on the server and passes them down to your client components. +Setting `lang={await getLocale()}` keeps the `` element's `lang` attribute in sync with the language your users see — important for accessibility and SEO. + --- ## Step 6: Mark content for translation diff --git a/docs/en-US/node/api/with-gt.mdx b/docs/en-US/node/api/with-gt.mdx index f6a70dfb..b19c9a7a 100644 --- a/docs/en-US/node/api/with-gt.mdx +++ b/docs/en-US/node/api/with-gt.mdx @@ -61,7 +61,7 @@ app.get('/api/greeting', (req, res) => { ```js title="server.js" import express from 'express'; -import { initializeGT, withGT, getGT } from 'gt-node'; +import { initializeGT, withGT, getGT, getRequestLocale } from 'gt-node'; initializeGT({ defaultLocale: 'en-US', @@ -72,7 +72,7 @@ initializeGT({ const app = express(); app.use((req, res, next) => { - const locale = req.headers['accept-language']?.split(',')[0] || 'en-US'; + const locale = getRequestLocale(req); withGT(locale, () => { next(); }); @@ -89,7 +89,7 @@ app.get('/api/greeting', async (req, res) => { ```js title="handler.js" import { withGT, getGT } from 'gt-node'; -export async function handleRequest(locale: string) { +export async function handleRequest(locale) { return withGT(locale, async () => { const gt = await getGT(); return gt('Welcome to our app!'); diff --git a/docs/en-US/node/tutorials/quickstart.mdx b/docs/en-US/node/tutorials/quickstart.mdx index 984a3935..9dd24f80 100644 --- a/docs/en-US/node/tutorials/quickstart.mdx +++ b/docs/en-US/node/tutorials/quickstart.mdx @@ -84,13 +84,13 @@ This configures the library with your supported languages and project credential ## Step 4: Set locale context per request -Each request needs to know which language to use. Use **`withGT`** to wrap your request handlers — it uses async local storage so translation functions automatically pick up the right locale: +Each request needs to know which language to use. Use **`withGT`** to wrap your request handlers — it uses async local storage so translation functions automatically pick up the right locale. Resolve the locale with [`getRequestLocale`](/docs/node/api/get-request-locale), which matches the request's `Accept-Language` header against your configured locales: ```js title="server.js" -import { withGT } from 'gt-node'; +import { withGT, getRequestLocale } from 'gt-node'; app.use((req, res, next) => { - const locale = req.headers['accept-language']?.split(',')[0] || 'en'; + const locale = getRequestLocale(req); withGT(locale, () => next()); }); ``` @@ -212,7 +212,14 @@ Here's a complete Express server with all the pieces together: ```js title="server.js" import express from 'express'; -import { initializeGT, withGT, getGT, msg, getMessages } from 'gt-node'; +import { + initializeGT, + withGT, + getRequestLocale, + getGT, + msg, + getMessages, +} from 'gt-node'; // Initialize GT before anything else initializeGT({ @@ -228,7 +235,7 @@ const app = express(); // Set locale context for each request app.use((req, res, next) => { - const locale = req.headers['accept-language']?.split(',')[0] || 'en'; + const locale = getRequestLocale(req); withGT(locale, () => next()); }); diff --git a/docs/en-US/react/api/components/gtprovider.mdx b/docs/en-US/react/api/components/gtprovider.mdx index 3c447eb7..f1cc09c3 100644 --- a/docs/en-US/react/api/components/gtprovider.mdx +++ b/docs/en-US/react/api/components/gtprovider.mdx @@ -153,4 +153,4 @@ createRoot(document.getElementById('root')!).render(); - Learn more about the [`` component](/docs/react/guides/t) for translating text and components. - Learn how to load translations with [`loadTranslations`](/docs/react/api/config/load-translations). -- See the [React Quickstart](/docs/react) for a full SPA setup walkthrough. +- See the [server-rendered quickstart](/docs/react/tutorials/quickstart-ssr) for a full setup walkthrough, or the [SPA quickstart](/docs/react/tutorials/quickstart-spa) for apps that don't need a provider. diff --git a/docs/en-US/react/index.mdx b/docs/en-US/react/index.mdx index d6a13a09..30f5dd85 100644 --- a/docs/en-US/react/index.mdx +++ b/docs/en-US/react/index.mdx @@ -3,411 +3,41 @@ title: React Quickstart description: Add multiple languages to your React app in under 10 minutes --- -By the end of this guide, your React app will display content in multiple languages, with a language switcher your users can interact with. +## Getting started -**Prerequisites:** -- A React app (Vite, Create React App, or similar) -- Node.js 18+ +Add translations to your React app with `gt-react`. Setup differs depending on how your app renders, so choose the quickstart that matches your setup: - - **Want automatic setup?** Run `npx gt@latest` to configure everything with the [Setup Wizard](/docs/cli/init). This guide covers manual setup. - - ---- - -## Step 1: Install the packages - -`gt-react` is the library that powers translations in your app. `gt` is the CLI tool that prepares translations for production. - - - - ```bash - npm i gt-react - npm i -D gt - ``` - - - ```bash - yarn add gt-react - yarn add --dev gt - ``` - - - ```bash - bun add gt-react - bun add --dev gt - ``` - - - ```bash - pnpm add gt-react - pnpm add --save-dev gt - ``` - - - ---- - -## Step 2: Create a translation config file - -Create a **`gt.config.json`** file in your project root. This tells the library which languages you support: - -```json title="gt.config.json" -{ - "defaultLocale": "en", - "locales": ["es", "fr", "ja"], - "files": { - "gt": { - "output": "public/_gt/[locale].json" - } - } -} -``` - -- **`defaultLocale`** — the language your app is written in (your source language). -- **`locales`** — the languages you want to translate into. Pick any from the [supported locales list](/docs/platform/supported-locales). -- **`files`** — tells the CLI where to save translation files. The `output` path should match the import path in your `loadTranslations` function (Step 3). + + + For client-side rendered apps (Vite, Create React App, webpack). Initialize once with `initializeGTSPA()` — no provider needed. + + + For SSR frameworks (TanStack Start, React Router, custom SSR). Load a translations snapshot on the server and pass it to ``. + + - **Using Vite?** Set the output path to `"src/_gt/[locale].json"` instead of `"public/_gt/[locale].json"`. Vite imports translation files as modules, so they should live inside `src/` rather than `public/`. - - ---- - -## Step 3: Create a translation loader - -`gt-react` runs entirely on the client, so it needs a function to load translation files at runtime. Create a `loadTranslations` file: - -```ts title="src/loadTranslations.ts" -export default async function loadTranslations(locale: string) { - try { - const translations = await import(`../public/_gt/${locale}.json`); - return translations.default; - } catch (error) { - console.warn(`No translations found for ${locale}`); - return {}; - } -} -``` - -This function loads JSON translation files from your `public/_gt/` directory. The CLI generates these files when you run `npx gt translate`. - - - - Since Vite translation files live in `src/_gt/` (see Step 2), update the import path: - - ```ts title="src/loadTranslations.ts" - export default async function loadTranslations(locale: string) { - try { - const translations = await import(`./_gt/${locale}.json`); - return translations.default; - } catch (error) { - console.warn(`No translations found for ${locale}`); - return {}; - } - } - ``` - - - CRA's webpack config blocks dynamic `import()` from outside `src/`. Use `fetch()` instead: - - ```ts title="src/loadTranslations.ts" - export default async function loadTranslations(locale: string) { - try { - const response = await fetch(`${process.env.PUBLIC_URL}/_gt/${locale}.json`); - if (!response.ok) throw new Error('Not found'); - return await response.json(); - } catch (error) { - console.warn(`No translations found for ${locale}`); - return {}; - } - } - ``` - - - ---- - -## Step 4: Initialize the library - -Call **`initializeGTSPA`** in your entry point, before rendering your app. It takes your config and translation loader, determines the user's locale, and loads the translations for it: - -```tsx title="src/main.tsx" -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; -import { initializeGTSPA } from 'gt-react'; -import gtConfig from '../gt.config.json'; -import loadTranslations from './loadTranslations'; -import App from './App'; - -// Resolves once the initial translations are loaded -await initializeGTSPA({ - ...gtConfig, - loadTranslations, -}); - -createRoot(document.getElementById('root')!).render( - - - -); -``` - -`initializeGTSPA` runs once at startup — the configuration is immutable for the lifetime of the app. After it resolves, every component and hook in your app can access translations. You don't need to wrap your app in a provider. - - - - CRA restricts imports to files inside `src/` and may not support top-level `await`, so inline the config and render inside `.then()`: - - ```tsx title="src/index.tsx" - import { StrictMode } from 'react'; - import { createRoot } from 'react-dom/client'; - import { initializeGTSPA } from 'gt-react'; - import loadTranslations from './loadTranslations'; - import App from './App'; - - initializeGTSPA({ - defaultLocale: 'en', - locales: ['es', 'fr', 'ja'], - loadTranslations, - }).then(() => { - createRoot(document.getElementById('root')!).render( - - - - ); - }); - ``` - - - ---- - -## Step 5: Mark content for translation - -Now, wrap any text you want translated with the **``** component. `` stands for "translate": - -```tsx title="src/components/Welcome.tsx" -import { T } from 'gt-react'; - -export default function Welcome() { - return ( -
- -

Welcome to my app

-

This content will be translated automatically.

-
-
- ); -} -``` - -You can wrap as much or as little JSX as you want inside ``. Everything inside it — text, nested elements, even formatting — gets translated as a unit. - ---- - -## Step 6: Add a language switcher - -Drop in a **``** so users can change languages: - -```tsx title="src/components/Welcome.tsx" -import { T, LocaleSelector } from 'gt-react'; - -export default function Welcome() { - return ( -
- - -

Welcome to my app

-

This content will be translated automatically.

-
-
- ); -} -``` - -`LocaleSelector` renders a dropdown populated with the languages from your `gt.config.json`. - ---- - -## Step 7: Set up environment variables (optional) - -To see translations in development, you need API keys from General Translation. These enable **on-demand translation** — your app translates content in real time as you develop. - -Create a **`.env.local`** file with the correct prefix for your bundler: - - - - ```bash title=".env.local" - VITE_GT_PROJECT_ID="your-project-id" - VITE_GT_DEV_API_KEY="your-dev-api-key" - ``` - - `gt-react` reads these automatically during initialization — no extra code needed. The dev API key is only read in development, so it stays out of production bundles. - - - ```bash title=".env.local" - REACT_APP_GT_PROJECT_ID="your-project-id" - REACT_APP_GT_DEV_API_KEY="your-dev-api-key" - ``` - - CRA environment variables are not read automatically — pass them to `initializeGTSPA`: - - ```tsx title="src/index.tsx" - initializeGTSPA({ - defaultLocale: 'en', - locales: ['es', 'fr', 'ja'], - loadTranslations, - projectId: process.env.REACT_APP_GT_PROJECT_ID, - devApiKey: - process.env.NODE_ENV === 'development' - ? process.env.REACT_APP_GT_DEV_API_KEY - : undefined, - }); - ``` - - - -Get your free keys at [dash.generaltranslation.com](https://dash.generaltranslation.com/signup) or by running: - -```bash -npx gt auth -``` - - - For development, use a key starting with `gtx-dev-`. Production keys (`gtx-api-`) are for CI/CD only. - - Client-side bundlers like Vite and CRA require environment variables to use specific prefixes (`VITE_` or `REACT_APP_`) to be exposed to the browser. Bare `GT_API_KEY` will not be available at runtime. - - - - - Yes. Without API keys, `gt-react` works as a standard i18n library. You won't get on-demand translation in development, but you can still: - - Provide your own translation files manually - - Use all components (``, ``, `LocaleSelector`, etc.) - - Run `npx gt generate` to create translation file templates, then translate them yourself - - - ---- - -## Step 8: See it working - -Start your dev server: - - - - ```bash - npm run dev - ``` - - - ```bash - yarn dev - ``` - - - ```bash - bun dev - ``` - - - ```bash - pnpm dev - ``` - - - -Open your app and use the language dropdown to switch languages. You should see your content translated. - - - **Note:** In development, translations happen on-demand — content may briefly appear in your source language the first time you switch to a new language, then update once the translation is ready. In production, translations are pre-generated and load instantly. + **Want automatic setup?** Run `npx gt@latest` to configure everything with the [Setup Wizard](/docs/cli/init). ---- - -## Step 9: Translate strings (not just JSX) - -For plain strings — like `placeholder` attributes, `aria-label` values, or `alt` text — use the **`useGT`** hook: - -```tsx title="src/components/ContactForm.tsx" -import { useGT } from 'gt-react'; - -export default function ContactForm() { - const gt = useGT(); - - return ( -
- - -
- ); -} -``` - ---- - -## Step 10: Deploy to production - -In production, translations are pre-generated at build time (no real-time API calls). Add the translate command to your build script: - -```json title="package.json" -{ - "scripts": { - "build": "npx gt translate && " - } -} -``` +## How the two setups differ -Set your **production** environment variables in your hosting provider (Vercel, Netlify, etc.): +| | SPA | Server-rendered | +| --- | --- | --- | +| Initialization | `initializeGTSPA()` in your entry point, awaited before render | `initializeGT()` at module scope in your root route | +| Translation loading | In the browser, during initialization | On the server, per request, via `getTranslationsSnapshot(locale)` | +| Provider | None | `` | +| Locale detection | Automatic (cookie, then browser language) | Your route loader resolves it from the request | -```bash -GT_PROJECT_ID=your-project-id -GT_API_KEY=gtx-api-your-production-key -``` +Everything after setup is identical: mark content with [``](/docs/react/guides/t), translate strings with [`useGT`](/docs/react/guides/strings), and pre-generate production translations with [`npx gt translate`](/docs/cli/translate). - - Production keys start with `gtx-api-` (not `gtx-dev-`). Get one from [dash.generaltranslation.com](https://dash.generaltranslation.com). Never publicly expose your `GT_API_KEY`. + + **Using a full-stack framework?** [`gt-next`](/docs/next) covers Next.js and [`gt-tanstack-start`](/docs/tanstack-start) covers TanStack Start — both build on `gt-react` and handle the server integration for you. -That's it — your app is now multilingual. 🎉 - ---- - -## Troubleshooting - - - - `gt-react` stores the user's language preference in a cookie called `generaltranslation.locale`. If you previously tested with a different language, this cookie may override your selection. Clear your cookies and try again. - - - [Chrome](https://support.google.com/chrome/answer/95647) - - [Firefox](https://support.mozilla.org/en-US/kb/delete-cookies-remove-info-websites-stored) - - [Safari](https://support.apple.com/en-mn/guide/safari/sfri11471/16.0/mac/11.0) - - - This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. - - - Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` prop to help: - - ```jsx - Apple - ``` - - Both `` and `useGT()` support the `$context` option. - - - ---- - ## Next steps -- [**`` Component Guide**](/docs/react/guides/t) — Learn about variables, plurals, and advanced translation patterns -- [**String Translation Guide**](/docs/react/guides/strings) — Deep dive into `useGT` -- [**Variable Components**](/docs/react/guides/variables) — Handle dynamic content with ``, ``, ``, and `` -- [**Pluralization**](/docs/react/api/components/plural) — Handle plural forms with the `` component -- [**Deploying to Production**](/docs/react/tutorials/quickdeploy) — CI/CD setup, caching, and performance optimization -- [**Shared Strings**](/docs/react/guides/shared-strings) — Translate text in arrays, config objects, and shared data with `msg()` +- [Introduction](/docs/react/introduction) - What `gt-react` does and how it works +- [`` component guide](/docs/react/guides/t) - Translate JSX content +- [String translation guide](/docs/react/guides/strings) - Translate plain strings with `useGT` +- [Deploying to production](/docs/react/tutorials/quickdeploy) - CI/CD setup for translations diff --git a/docs/en-US/react/meta.json b/docs/en-US/react/meta.json index 193b540d..109d0966 100644 --- a/docs/en-US/react/meta.json +++ b/docs/en-US/react/meta.json @@ -28,7 +28,8 @@ "./api/helpers", "./api/types", "---Tutorials---", - "./tutorials/quickstart", + "./tutorials/quickstart-spa", + "./tutorials/quickstart-ssr", "./tutorials/quickdeploy", "./tutorials/mini-shop" ], diff --git a/docs/en-US/react/tutorials/quickstart-spa.mdx b/docs/en-US/react/tutorials/quickstart-spa.mdx new file mode 100644 index 00000000..5685f9a5 --- /dev/null +++ b/docs/en-US/react/tutorials/quickstart-spa.mdx @@ -0,0 +1,442 @@ +--- +title: SPA Quickstart +description: Add multiple languages to your single-page React app in under 10 minutes +--- + +By the end of this guide, your single-page React app will display content in multiple languages, with a language switcher your users can interact with. + +In a single-page app, `gt-react` runs entirely in the browser — you initialize it once at startup with `initializeGTSPA()`, and you don't need a provider component. + +**Prerequisites:** +- A client-side rendered React app (Vite, Create React App, webpack, or similar) +- Node.js 18+ + + + **Want automatic setup?** Run `npx gt@latest` to configure everything with the [Setup Wizard](/docs/cli/init). This guide covers manual setup. + + + + **Server-rendered app?** If your framework renders on the server (TanStack Start, React Router, or a custom SSR setup), follow the [server-rendered quickstart](/docs/react/tutorials/quickstart-ssr) instead. + + +--- + +## Step 1: Install the packages + +`gt-react` is the library that powers translations in your app. `gt` is the CLI tool that prepares translations for production, and `@generaltranslation/compiler` is a build plugin for your bundler. + + + + ```bash + npm i gt-react + npm i -D gt @generaltranslation/compiler + ``` + + + ```bash + yarn add gt-react + yarn add --dev gt @generaltranslation/compiler + ``` + + + ```bash + bun add gt-react + bun add --dev gt @generaltranslation/compiler + ``` + + + ```bash + pnpm add gt-react + pnpm add --save-dev gt @generaltranslation/compiler + ``` + + + +--- + +## Step 2: Create a translation config file + +Create a **`gt.config.json`** file in your project root. This tells the library which languages you support: + +```json title="gt.config.json" +{ + "defaultLocale": "en", + "locales": ["es", "fr", "ja"], + "files": { + "gt": { + "output": "src/_gt/[locale].json" + } + } +} +``` + +- **`defaultLocale`** — the language your app is written in (your source language). +- **`locales`** — the languages you want to translate into. Pick any from the [supported locales list](/docs/platform/supported-locales). +- **`files`** — tells the CLI where to save translation files. The `output` path should match the import path in your `loadTranslations` function (Step 4). + + + **File location:** Bundlers like Vite import translation files as modules, so they should live inside `src/`. If you load translations over HTTP instead (see the Create React App note in Step 4), use `"public/_gt/[locale].json"`. + + +--- + +## Step 3: Add the compiler plugin + +Add the GT compiler plugin to your bundler config. It analyzes your source files at build time — validating translation calls and precomputing translation metadata so that work doesn't happen in the browser: + +```ts title="vite.config.ts" +import react from '@vitejs/plugin-react'; +import { vite as gtCompiler } from '@generaltranslation/compiler'; // [!code highlight] +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [gtCompiler(), react()], // [!code highlight] +}); +``` + + + + `@generaltranslation/compiler` also exports plugins for other bundlers — import the one that matches yours: + + ```ts + import { webpack as gtCompiler } from '@generaltranslation/compiler'; + // also available: rollup, esbuild + ``` + + + +See the [compiler concepts page](/docs/react/concepts/compiler) for everything the compiler can do, including automatic JSX wrapping. + +--- + +## Step 4: Create a translation loader + +In an SPA, `gt-react` needs a function to load translation files in the browser at runtime. Create a `loadTranslations` file: + +```ts title="src/loadTranslations.ts" +export default async function loadTranslations(locale: string) { + try { + const translations = await import(`./_gt/${locale}.json`); + return translations.default; + } catch (error) { + console.warn(`No translations found for ${locale}`); + return {}; + } +} +``` + +This function loads JSON translation files from your `src/_gt/` directory. The CLI generates these files when you run `npx gt translate`. + + + + CRA's webpack config blocks dynamic `import()` from outside `src/`. Store translations in `public/_gt/` and use `fetch()` instead: + + ```ts title="src/loadTranslations.ts" + export default async function loadTranslations(locale: string) { + try { + const response = await fetch(`${process.env.PUBLIC_URL}/_gt/${locale}.json`); + if (!response.ok) throw new Error('Not found'); + return await response.json(); + } catch (error) { + console.warn(`No translations found for ${locale}`); + return {}; + } + } + ``` + + + +--- + +## Step 5: Initialize the library + +Call **`initializeGTSPA`** once at startup, before your app renders. It takes your config and translation loader, determines the user's locale, and loads the translations for it. + +The most robust pattern is a small entry module that initializes GT first, then loads the rest of the app: + +```ts title="src/index.ts" +import { initializeGTSPA } from 'gt-react'; +import gtConfig from '../gt.config.json'; +import loadTranslations from './loadTranslations'; + +await initializeGTSPA({ + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, + loadTranslations, +}); + +await import('./main'); // render the app only after GT is ready +``` + +```tsx title="src/main.tsx" +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App'; + +createRoot(document.getElementById('root')!).render( + + + +); +``` + +Then update the module script tag in your `index.html` to point at the new entry: change its `src` from `/src/main.tsx` to `/src/index.ts`. + +`initializeGTSPA` runs once at startup — the configuration is immutable for the lifetime of the app. After it resolves, every component and hook in your app can access translations. **You don't need to wrap your app in a provider.** + + + + CRA may not support top-level `await`, so render inside `.then()`: + + ```tsx title="src/index.tsx" + import { StrictMode } from 'react'; + import { createRoot } from 'react-dom/client'; + import { initializeGTSPA } from 'gt-react'; + import loadTranslations from './loadTranslations'; + import App from './App'; + + initializeGTSPA({ + defaultLocale: 'en', + locales: ['es', 'fr', 'ja'], + loadTranslations, + }).then(() => { + createRoot(document.getElementById('root')!).render( + + + + ); + }); + ``` + + + +--- + +## Step 6: Mark content for translation + +Now, wrap any text you want translated with the **``** component. `` stands for "translate": + +```tsx title="src/components/Welcome.tsx" +import { T } from 'gt-react'; + +export default function Welcome() { + return ( +
+ +

Welcome to my app

+

This content will be translated automatically.

+
+
+ ); +} +``` + +You can wrap as much or as little JSX as you want inside ``. Everything inside it — text, nested elements, even formatting — gets translated as a unit. + +--- + +## Step 7: Add a language switcher + +Drop in a **``** so users can change languages: + +```tsx title="src/components/Welcome.tsx" +import { T, LocaleSelector } from 'gt-react'; + +export default function Welcome() { + return ( +
+ + +

Welcome to my app

+

This content will be translated automatically.

+
+
+ ); +} +``` + +`LocaleSelector` renders a dropdown populated with the languages from your `gt.config.json`. + +--- + +## Step 8: Set up environment variables (optional) + +To see translations in development, you need API keys from General Translation. These enable **on-demand translation** — your app translates content in real time as you develop. + +Create a **`.env.local`** file with the correct prefix for your bundler: + + + + ```bash title=".env.local" + VITE_GT_PROJECT_ID="your-project-id" + VITE_GT_DEV_API_KEY="your-dev-api-key" + ``` + + `gt-react` reads these automatically during initialization — no extra code needed. The dev API key is only read in development, so it stays out of production bundles. + + + ```bash title=".env.local" + REACT_APP_GT_PROJECT_ID="your-project-id" + REACT_APP_GT_DEV_API_KEY="your-dev-api-key" + ``` + + CRA environment variables are not read automatically — pass them to `initializeGTSPA`: + + ```tsx title="src/index.tsx" + initializeGTSPA({ + defaultLocale: 'en', + locales: ['es', 'fr', 'ja'], + loadTranslations, + projectId: process.env.REACT_APP_GT_PROJECT_ID, + devApiKey: + process.env.NODE_ENV === 'development' + ? process.env.REACT_APP_GT_DEV_API_KEY + : undefined, + }); + ``` + + + +Get your free keys at [dash.generaltranslation.com](https://dash.generaltranslation.com/signup) or by running: + +```bash +npx gt auth +``` + + + For development, use a key starting with `gtx-dev-`. Production keys (`gtx-api-`) are for CI/CD only. + + Client-side bundlers like Vite and CRA require environment variables to use specific prefixes (`VITE_` or `REACT_APP_`) to be exposed to the browser. Bare `GT_API_KEY` will not be available at runtime. + + + + + Yes. Without API keys, `gt-react` works as a standard i18n library. You won't get on-demand translation in development, but you can still: + - Provide your own translation files manually + - Use all components (``, ``, `LocaleSelector`, etc.) + - Run `npx gt generate` to create translation file templates, then translate them yourself + + + +--- + +## Step 9: See it working + +Start your dev server: + + + + ```bash + npm run dev + ``` + + + ```bash + yarn dev + ``` + + + ```bash + bun dev + ``` + + + ```bash + pnpm dev + ``` + + + +Open your app and use the language dropdown to switch languages. You should see your content translated. + + + **Note:** In development, translations happen on-demand — content may briefly appear in your source language the first time you switch to a new language, then update once the translation is ready. In production, translations are pre-generated and load instantly. + + +--- + +## Step 10: Translate strings (not just JSX) + +For plain strings — like `placeholder` attributes, `aria-label` values, or `alt` text — use the **`useGT`** hook: + +```tsx title="src/components/ContactForm.tsx" +import { useGT } from 'gt-react'; + +export default function ContactForm() { + const gt = useGT(); + + return ( +
+ + +
+ ); +} +``` + +--- + +## Step 11: Deploy to production + +In production, translations are pre-generated at build time (no real-time API calls). Add the translate command to your build script: + +```json title="package.json" +{ + "scripts": { + "build": "npx gt translate && " + } +} +``` + +Set your **production** environment variables in your hosting provider (Vercel, Netlify, etc.): + +```bash +GT_PROJECT_ID=your-project-id +GT_API_KEY=gtx-api-your-production-key +``` + + + Production keys start with `gtx-api-` (not `gtx-dev-`). Get one from [dash.generaltranslation.com](https://dash.generaltranslation.com). Never publicly expose your `GT_API_KEY`. + + +That's it — your app is now multilingual. 🎉 + +--- + +## Troubleshooting + + + + `gt-react` stores the user's language preference in a cookie called `generaltranslation.locale`. If you previously tested with a different language, this cookie may override your selection. Clear your cookies and try again. + + - [Chrome](https://support.google.com/chrome/answer/95647) + - [Firefox](https://support.mozilla.org/en-US/kb/delete-cookies-remove-info-websites-stored) + - [Safari](https://support.apple.com/en-mn/guide/safari/sfri11471/16.0/mac/11.0) + + + This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. + + + Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` prop to help: + + ```jsx + Apple + ``` + + Both `` and `useGT()` support the `$context` option. + + + +--- + +## Next steps + +- [**`` Component Guide**](/docs/react/guides/t) — Learn about variables, plurals, and advanced translation patterns +- [**String Translation Guide**](/docs/react/guides/strings) — Deep dive into `useGT` +- [**Variable Components**](/docs/react/guides/variables) — Handle dynamic content with ``, ``, ``, and `` +- [**Pluralization**](/docs/react/api/components/plural) — Handle plural forms with the `` component +- [**Deploying to Production**](/docs/react/tutorials/quickdeploy) — CI/CD setup, caching, and performance optimization +- [**Shared Strings**](/docs/react/guides/shared-strings) — Translate text in arrays, config objects, and shared data with `msg()` diff --git a/docs/en-US/react/tutorials/quickstart-ssr.mdx b/docs/en-US/react/tutorials/quickstart-ssr.mdx new file mode 100644 index 00000000..af6636c7 --- /dev/null +++ b/docs/en-US/react/tutorials/quickstart-ssr.mdx @@ -0,0 +1,291 @@ +--- +title: Server-rendered Quickstart +description: Add multiple languages to your server-rendered React app in under 10 minutes +--- + +By the end of this guide, your server-rendered React app will display content in multiple languages, with a language switcher your users can interact with. + +Server-rendered apps work differently from SPAs: the server resolves the user's locale, loads a translations snapshot, and passes both to a `` so the first render is already translated. There is no client-side loading state. + +**Prerequisites:** +- A server-rendered React app (TanStack Start, React Router, or a custom SSR setup) +- Node.js 18+ + + + **Using TanStack Start?** Use [`gt-tanstack-start`](/docs/tanstack-start) instead — it re-exports the `gt-react` API and adds `parseLocale()` for isomorphic locale detection. The setup below is the same, minus writing your own locale resolver. + + + + **Client-side only app?** If your app renders entirely in the browser (Vite, Create React App), follow the [SPA quickstart](/docs/react/tutorials/quickstart-spa) instead — it skips the provider entirely. + + +--- + +## Step 1: Install the packages + +`gt-react` is the library that powers translations in your app. `gt` is the CLI tool that prepares translations for production. + + + + ```bash + npm i gt-react + npm i -D gt + ``` + + + ```bash + yarn add gt-react + yarn add --dev gt + ``` + + + ```bash + bun add gt-react + bun add --dev gt + ``` + + + ```bash + pnpm add gt-react + pnpm add --save-dev gt + ``` + + + +--- + +## Step 2: Create a translation config file + +Create a **`gt.config.json`** file in your project root. This tells the library which languages you support: + +```json title="gt.config.json" +{ + "defaultLocale": "en", + "locales": ["es", "fr", "ja"], + "files": { + "gt": { + "output": "src/_gt/[locale].json" + } + } +} +``` + +- **`defaultLocale`** — the language your app is written in (your source language). +- **`locales`** — the languages you want to translate into. Pick any from the [supported locales list](/docs/platform/supported-locales). +- **`files`** — tells the CLI where to save translation files. The `output` path should match the import path in your `loadTranslations` function (Step 3). + +--- + +## Step 3: Create a translation loader + +Create a `loadTranslations` function that loads a locale's translation file. On the server this runs during rendering; the CLI generates the files when you run `npx gt translate`: + +```ts title="src/loadTranslations.ts" +export default async function loadTranslations(locale: string) { + try { + const translations = await import(`./_gt/${locale}.json`); + return translations.default; + } catch (error) { + return {}; + } +} +``` + +--- + +## Step 4: Initialize the library + +Call **`initializeGT`** at module scope in a file that loads on both the server and the client — your root route or layout is the natural place. It registers your config and translation loader once; the configuration is immutable for the lifetime of the app: + +```tsx title="src/routes/root.tsx" +import { initializeGT } from 'gt-react'; +import gtConfig from '../../gt.config.json'; +import loadTranslations from '../loadTranslations'; + +initializeGT({ + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, + loadTranslations, +}); +``` + +Unlike `initializeGTSPA`, `initializeGT` doesn't load any translations itself — that happens per request in the next step. + +--- + +## Step 5: Load translations on the server + +In your root route's loader (or equivalent server handler), resolve the request locale and fetch a translations snapshot with **`getTranslationsSnapshot`**, then pass both to **``**: + +```tsx title="src/routes/root.tsx" +import { GTProvider, getTranslationsSnapshot } from 'gt-react'; + +// In your route loader (exact API depends on your framework) +export async function loader({ request }) { + const locale = resolveLocale(request); // [!code highlight] + return { + locale, + translations: await getTranslationsSnapshot(locale), // [!code highlight] + }; +} + +export default function Root({ children }) { + const { locale, translations } = useLoaderData(); + return ( + + {children} + + ); +} +``` + +For `resolveLocale`, read the **`generaltranslation.locale`** cookie first — that's where `gt-react` persists the user's language choice — and fall back to the request's `Accept-Language` header or your default locale. + + + **No loading state:** `` renders synchronously from the snapshot. Whatever loading behavior you want (pending UI, streaming) belongs in your framework's route loader, not in GT. + + +--- + +## Step 6: Mark content for translation + +Wrap any text you want translated with the **``** component. `` stands for "translate": + +```tsx title="src/components/Welcome.tsx" +import { T } from 'gt-react'; + +export default function Welcome() { + return ( +
+ +

Welcome to my app

+

This content will be translated automatically.

+
+
+ ); +} +``` + +For plain strings — like `placeholder` attributes or `aria-label` values — use the **`useGT`** hook: + +```tsx title="src/components/ContactForm.tsx" +import { useGT } from 'gt-react'; + +export default function ContactForm() { + const gt = useGT(); + return ; +} +``` + +--- + +## Step 7: Add a language switcher + +Drop in a **``** so users can change languages: + +```tsx title="src/components/Header.tsx" +import { LocaleSelector } from 'gt-react'; + +export default function Header() { + return ; +} +``` + +When the user picks a language, `gt-react` persists the choice in the `generaltranslation.locale` cookie and reloads the page, so the server re-renders everything in the new locale. + +--- + +## Step 8: Set up environment variables (optional) + +To see translations in development, you need API keys from General Translation. These enable **on-demand translation** — your app translates content in real time as you develop. + +If your framework builds with Vite, `gt-react` reads these automatically during initialization: + +```bash title=".env.local" +VITE_GT_PROJECT_ID="your-project-id" +VITE_GT_DEV_API_KEY="your-dev-api-key" +``` + +Otherwise, pass credentials to `initializeGT` yourself: + +```ts +initializeGT({ + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, + loadTranslations, + projectId: process.env.GT_PROJECT_ID, + devApiKey: + process.env.NODE_ENV === 'development' + ? process.env.GT_DEV_API_KEY + : undefined, +}); +``` + +Get your free keys at [dash.generaltranslation.com](https://dash.generaltranslation.com/signup) or by running: + +```bash +npx gt auth +``` + + + For development, use a key starting with `gtx-dev-`. Production keys (`gtx-api-`) are for CI/CD only. + + +--- + +## Step 9: Deploy to production + +In production, translations are pre-generated at build time (no real-time API calls). Add the translate command to your build script: + +```json title="package.json" +{ + "scripts": { + "build": "npx gt translate && " + } +} +``` + +Set your **production** environment variables in your hosting provider: + +```bash +GT_PROJECT_ID=your-project-id +GT_API_KEY=gtx-api-your-production-key +``` + + + Production keys start with `gtx-api-` (not `gtx-dev-`). Get one from [dash.generaltranslation.com](https://dash.generaltranslation.com). Never publicly expose your `GT_API_KEY`. + + +That's it — your app is now multilingual. 🎉 + +--- + +## Troubleshooting + + + + Make sure your locale resolver reads the `generaltranslation.locale` cookie. If the server ignores it, the client and server will disagree about the current locale. + + + This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. + + + Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` prop to help: + + ```jsx + Apple + ``` + + Both `` and `useGT()` support the `$context` option. + + + +--- + +## Next steps + +- [**`` API**](/docs/react/api/components/gtprovider) — Full reference for the provider's props +- [**TanStack Start Quickstart**](/docs/tanstack-start) — The same setup with `parseLocale()` included +- [**`` Component Guide**](/docs/react/guides/t) — Learn about variables, plurals, and advanced translation patterns +- [**String Translation Guide**](/docs/react/guides/strings) — Deep dive into `useGT` +- [**Deploying to Production**](/docs/react/tutorials/quickdeploy) — CI/CD setup, caching, and performance optimization diff --git a/docs/en-US/tanstack-start/index.mdx b/docs/en-US/tanstack-start/index.mdx index 43249ab6..5cff7602 100644 --- a/docs/en-US/tanstack-start/index.mdx +++ b/docs/en-US/tanstack-start/index.mdx @@ -11,39 +11,35 @@ description: Internationalize your TanStack Start app with gt-tanstack-start ## Installation -Install `gt-tanstack-start`, `gt-react`, and the `gt` CLI: +Install `gt-tanstack-start` and the `gt` CLI: ```bash - npm i gt-tanstack-start gt-react + npm i gt-tanstack-start npm i -D gt ``` ```bash - yarn add gt-tanstack-start gt-react + yarn add gt-tanstack-start yarn add --dev gt ``` ```bash - bun add gt-tanstack-start gt-react + bun add gt-tanstack-start bun add --dev gt ``` ```bash - pnpm add gt-tanstack-start gt-react + pnpm add gt-tanstack-start pnpm add --save-dev gt ``` - - `gt-react` is required as a direct dependency so the `gt` CLI can detect `` components in your source code. - - ## Configuration ### `gt.config.json` @@ -62,17 +58,17 @@ Create a `gt.config.json` in your project root: } ``` - - Translation files **must** be inside `src/` for Vite's dynamic imports to work. Using `public/` will not work. + + **File location:** Translation files must be inside `src/` for Vite's dynamic imports to work. Using `public/` will not work. ### Translation loader -Create a `loadTranslations.ts` file in your project root: +Create a `loadTranslations.ts` file in `src/`: -```ts title="loadTranslations.ts" +```ts title="src/loadTranslations.ts" export default async function loadTranslations(locale: string) { - const translations = await import(`./src/_gt/${locale}.json`); + const translations = await import(`./_gt/${locale}.json`); return translations.default; } ``` @@ -84,6 +80,7 @@ Update `src/routes/__root.tsx` to initialize GT and provide translations. In the ```tsx title="src/routes/__root.tsx" import { HeadContent, + Outlet, Scripts, createRootRoute, } from '@tanstack/react-router' @@ -95,11 +92,12 @@ import { LocaleSelector, } from 'gt-tanstack-start' import gtConfig from '../../gt.config.json' -import loadTranslations from '../../loadTranslations' +import loadTranslations from '../loadTranslations' // Initialize GT at the module level initializeGT({ - ...gtConfig, + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, loadTranslations, }) @@ -117,10 +115,10 @@ export const Route = createRootRoute({ translations: await getTranslationsSnapshot(locale), } }, - shellComponent: RootDocument, + component: RootComponent, }) -function RootDocument({ children }: { children: React.ReactNode }) { +function RootComponent() { const { translations, locale } = Route.useLoaderData() return ( @@ -130,7 +128,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { - {children} + @@ -145,11 +143,11 @@ function RootDocument({ children }: { children: React.ReactNode }) { ## Usage -Wrap content in `` to translate it. Import `` from `gt-react`: +Wrap content in `` to translate it: ```tsx title="src/routes/index.tsx" import { createFileRoute } from '@tanstack/react-router' -import { T } from 'gt-react' +import { T } from 'gt-tanstack-start' export const Route = createFileRoute('/')({ component: Home }) @@ -164,7 +162,7 @@ function Home() { ``` - Import `` from `gt-react` (not `gt-tanstack-start`). The `gt` CLI scans for `gt-react` imports to find translatable content. + **Note:** `gt-tanstack-start` re-exports the full `gt-react` API, so components like `` and hooks like `useGT` are all imported from `gt-tanstack-start`. The `gt` CLI detects translatable content from both `gt-tanstack-start` and `gt-react` imports. ## Generate translations @@ -233,7 +231,7 @@ Start the dev server:
-Visit [localhost:3000](http://localhost:3000) and use the locale selector to switch languages. Translations are loaded from local JSON files, so language switching is instant. +Visit [localhost:5173](http://localhost:5173) (or the port your dev server prints) and use the locale selector to switch languages. Translations are loaded from local JSON files, so language switching is instant. ## Deployment diff --git a/docs/en-US/tanstack-start/introduction.mdx b/docs/en-US/tanstack-start/introduction.mdx index 93efc958..ddf82ef9 100644 --- a/docs/en-US/tanstack-start/introduction.mdx +++ b/docs/en-US/tanstack-start/introduction.mdx @@ -37,10 +37,11 @@ The `initializeGT()` function configures the i18n manager. Call it at the top of ```tsx title="src/routes/__root.tsx" import { initializeGT } from 'gt-tanstack-start' import gtConfig from '../../gt.config.json' -import loadTranslations from '../../loadTranslations' +import loadTranslations from '../loadTranslations' initializeGT({ - ...gtConfig, + defaultLocale: gtConfig.defaultLocale, + locales: gtConfig.locales, loadTranslations, }) ``` @@ -73,7 +74,7 @@ The `` provides translation context to all child components. Pass th ```tsx title="src/routes/__root.tsx" import { GTProvider } from 'gt-tanstack-start' -function RootDocument({ children }: { children: React.ReactNode }) { +function RootComponent() { const { translations, locale } = Route.useLoaderData() return ( @@ -82,7 +83,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { - {children} + @@ -98,7 +99,7 @@ The provider has no loading state of its own. Because translations are loaded in The [``](/docs/react/api/components/t) component translates JSX content. Wrap any elements and they render in the user's language: ```tsx -import { T } from 'gt-react' +import { T } from 'gt-tanstack-start' function Welcome() { return ( @@ -111,7 +112,7 @@ function Welcome() { ``` - Import `` from `gt-react`, not from `gt-tanstack-start`. This ensures the `gt` CLI can detect your translatable content when generating translation files. + **Note:** Because `gt-tanstack-start` re-exports the full `gt-react` API, all components and hooks — ``, ``, `useGT`, `useLocale`, and the rest — are imported from `gt-tanstack-start`. The `gt` CLI detects translatable content from both `gt-tanstack-start` and `gt-react` imports. ## Locale selector @@ -130,6 +131,19 @@ function Nav() { } ``` +## Selective SSR + +`gt-tanstack-start` works with all of TanStack Start's rendering modes. Routes can opt out of server rendering with the `ssr` route option — `true` (full SSR), `false` (loader and component run on the client), or `'data-only'` (loader runs on the server, component renders on the client) — with no extra i18n setup: + +```tsx title="src/routes/spa.tsx" +export const Route = createFileRoute('/spa')({ + ssr: false, + component: SpaRoute, +}) +``` + +Because `parseLocale()` is isomorphic — on the server it resolves the locale from the locale cookie and the `Accept-Language` header, in the browser it reads the locale cookie — the root loader returns the same locale and translations wherever it runs, and the single root `` serves every route. + --- ## Next steps From b54a0d440156bcfd6771851b6f545171456b1db6 Mon Sep 17 00:00:00 2001 From: Ernest McCarter Date: Fri, 3 Jul 2026 18:09:10 -0700 Subject: [PATCH 3/3] docs: track odysseus API surface cleanup The odysseus branch removed getGTClass/useGTClass and the legacy initGT alias, replacing the locale-alias use case with a standalone resolveCanonicalLocale() helper. - locale-aliases: use resolveCanonicalLocale from gt-next instead of getGTClass().resolveCanonicalLocale() - with-gt-config: drop the initGT legacy callout and frontmatter mention Verified no docs reference the other removals (useVersionId, gt-next/types, generaltranslation/core, gt-i18n/fallbacks, useShouldTranslate). Co-Authored-By: Claude Fable 5 --- docs/en-US/next/api/config/with-gt-config.mdx | 9 +------ docs/en-US/next/guides/locale-aliases.mdx | 26 ++++++++----------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/docs/en-US/next/api/config/with-gt-config.mdx b/docs/en-US/next/api/config/with-gt-config.mdx index 228e0f21..682c2410 100644 --- a/docs/en-US/next/api/config/with-gt-config.mdx +++ b/docs/en-US/next/api/config/with-gt-config.mdx @@ -1,6 +1,6 @@ --- title: withGTConfig -description: API reference for the withGTConfig(), formerly initGT() +description: API reference for withGTConfig() --- ## Overview @@ -20,13 +20,6 @@ export default withGTConfig(nextConfig, { }); ``` - -**Legacy:** - -`initGT` is the legacy way to configure the `gt-next` library. It returns a function callback which is then called on the `NextConfig` object. -The props for both functions are the same, with the exception that `withGTProps` requires `NextConfig` to also be passed in. - - Use `withGTConfig` to: * Configure supported languages and default locale (a.k.a fallback language). * Configure timeout settings. diff --git a/docs/en-US/next/guides/locale-aliases.mdx b/docs/en-US/next/guides/locale-aliases.mdx index 7304a776..3bac581c 100644 --- a/docs/en-US/next/guides/locale-aliases.mdx +++ b/docs/en-US/next/guides/locale-aliases.mdx @@ -50,21 +50,20 @@ While aliases work seamlessly for routing, there are three places where you **mu 2. Alternate link tags in your page metadata 3. Alternate entries in your sitemap -GT provides the `resolveCanonicalLocale()` method to convert aliases back to their BCP 47 codes. You can access it via `getGTClass` from `gt-next`, which returns a `GTRuntime` instance with translation, formatting, and locale utilities. (The full `GT` class, which adds the project and file-management API client, remains available from `generaltranslation`.) +GT provides the `resolveCanonicalLocale()` function to convert aliases back to their BCP 47 codes. It is exported from `gt-next` and reads the custom mapping from your configuration: ```ts -import { getGTClass } from 'gt-next'; +import { resolveCanonicalLocale } from 'gt-next'; -const gtInstance = getGTClass(); -const canonicalLocale = gtInstance.resolveCanonicalLocale('cn'); +const canonicalLocale = resolveCanonicalLocale('cn'); // Returns: "zh" ``` For non-aliased locales, `resolveCanonicalLocale()` returns the input unchanged: ```ts -gtInstance.resolveCanonicalLocale('ja'); // "ja" -gtInstance.resolveCanonicalLocale('en-US'); // "en-US" +resolveCanonicalLocale('ja'); // "ja" +resolveCanonicalLocale('en-US'); // "en-US" ``` ### 1. HTML `lang` attribute @@ -74,7 +73,7 @@ The `` attribute tells browsers and search engines what language the In your root layout, resolve the locale before passing it to the `` tag: ```tsx title="app/[locale]/layout.tsx" -import { getGTClass } from 'gt-next'; +import { resolveCanonicalLocale } from 'gt-next'; export default function RootLayout({ children, @@ -83,8 +82,7 @@ export default function RootLayout({ children: React.ReactNode; params: { locale: string }; }) { - const gtInstance = getGTClass(); - const canonicalLocale = gtInstance.resolveCanonicalLocale(params.locale); + const canonicalLocale = resolveCanonicalLocale(params.locale); return ( @@ -102,20 +100,19 @@ Alternate links tell search engines which versions of a page exist in other lang ```tsx title="app/[locale]/layout.tsx" import type { Metadata } from 'next'; -import { getGTClass } from 'gt-next'; +import { resolveCanonicalLocale } from 'gt-next'; export async function generateMetadata({ params, }: { params: { locale: string }; }): Promise { - const gtInstance = getGTClass(); const locales = ['en-US', 'cn', 'ja', 'zh-Hant']; // Build alternates with canonical BCP 47 codes as keys const languages: Record = {}; for (const locale of locales) { - const canonical = gtInstance.resolveCanonicalLocale(locale); + const canonical = resolveCanonicalLocale(locale); languages[canonical] = `https://example.com/${locale}`; } @@ -149,10 +146,9 @@ If you use a [dynamic sitemap](https://nextjs.org/docs/app/api-reference/file-co ```ts title="app/sitemap.ts" import type { MetadataRoute } from 'next'; -import { getGTClass } from 'gt-next'; +import { resolveCanonicalLocale } from 'gt-next'; export default function sitemap(): MetadataRoute.Sitemap { - const gtInstance = getGTClass(); const locales = ['en-US', 'cn', 'ja', 'zh-Hant']; const baseUrl = 'https://example.com'; @@ -162,7 +158,7 @@ export default function sitemap(): MetadataRoute.Sitemap { // Build language alternates with canonical codes const languages: Record = {}; for (const locale of locales) { - const canonical = gtInstance.resolveCanonicalLocale(locale); + const canonical = resolveCanonicalLocale(locale); languages[canonical] = `${baseUrl}/${locale}${page}`; }