Strings

How to internationalise plain text strings using useGT and getGT

String translation provides direct access to text translations without JSX — ideal for attributes, object properties, and plain text values. Use useGT in synchronous components and getGT in asynchronous components.

Synchronous vs Asynchronous Use

  • Synchronous components: useGT hook for React components
  • Asynchronous components: getGT async function for async components

Quick start

Synchronous Components

import { useGT } from 'gt-next';

function MyComponent() {
  const t = useGT();
  return (
    <input 
      placeholder={t('Enter your email address')}
      title={t('Email address field')}
    />
  );
}

Asynchronous components

import { getGT } from 'gt-next/server';

async function MyServerComponent() {
  const t = await getGT();
  return (
    <input 
      placeholder={t('Enter your email address')}
      title={t('Email address field')}
    />
  );
}

When to Use String Translation

String translation is ideal when you need plain text rather than JSX:

HTML attributes

const t = useGT();

<input 
  placeholder={t('Search products…')}
  aria-label={t('Product search input')}
  title={t('Type to search our catalogue')}
/>

Object properties

const t = useGT();

const user = {
  name: 'John',
  role: 'admin',
  bio: t('Experienced software developer with 5 years’ experience in React'),
  status: t('Currently available for projects')
};

Configuration & constants

const t = useGT();

const navigationItems = [
  { label: t('Home'), href: '/' },
  { label: t('Products'), href: '/products' },
  { label: t('Contact'), href: '/contact' }
];

When to use <T> instead

Use the <T> component for JSX content:

// ✅ Use <T> for JSX content
<T><p>Welcome to <strong>our shop</strong>!</p></T>

// ✅ Use string translation for plain text
<input placeholder={t('Search products')} />

Using variables

Basic variables

Replace placeholders with dynamic values:

const t = useGT();
const itemCount = 5;

// String with placeholder
const message = t('You have {count} items in your cart', { count: itemCount });
// Result: "You have 5 items in your cart"

Multiple variables

const t = useGT();
const order = { id: 'ORD-123', total: 99.99, date: '2024-01-15' };

const confirmation = t(
  'Order {orderId} for ${total} was placed on {date}',
  { 
    orderId: order.id, 
    total: order.total, 
    date: order.date 
  }
);

ICU Message Format

For advanced formatting, use ICU syntax:

const t = useGT();
translate('There {count, plural, =0 {are no items} =1 {is one item} other {are {count} items}} in the basket', { count: 10 });

Learn more about the ICU Message Format in the Unicode documentation.

Examples

Form Inputs

import { useGT } from 'gt-next';

function ContactForm() {
  const t = useGT();
  
  return (
    <form>
      <input 
        type="email"
        placeholder={t('Enter your email address')}
        aria-label={t('Email input field')}
      />
      <textarea 
        placeholder={t('Tell us about your project…')}
        aria-label={t('Project description')}
      />
      <button type="submit">
        {t('Send message')}
      </button>
    </form>
  );
}
import { useGT } from 'gt-next';

function Navigation() {
  const t = useGT();
  
  const menuItems = [
    { label: t('Home'), href: '/', icon: 'home' },
    { label: t('About us'), href: '/about', icon: 'info' },
    { label: t('Services'), href: '/services', icon: 'briefcase' },
    { label: t('Contact'), href: '/contact', icon: 'mail' }
  ];

  return (
    <nav>
      {menuItems.map((item) => (
        <a key={item.href} href={item.href} title={item.label}>
          <Icon name={item.icon} />
          {item.label}
        </a>
      ))}
    </nav>
  );
}

Dynamic Content Factory

// utils/productData.js
export function getProductMessages(t) {
  return {
    categories: [
      { id: 'electronics', name: t('Electronics') },
      { id: 'clothing', name: t('Clothing') },
      { id: 'books', name: t('Books') }
    ],
    statusMessages: {
      available: t('In stock and ready to despatch'),
      backordered: t('Currently backordered - ships in 2–3 weeks'),  
      discontinued: t('This item has been discontinued')
    },
    errors: {
      notFound: t('Product not found'),
      outOfStock: t('Sorry, this item is currently out of stock')
    }
  };
}

// components/ProductCard.jsx
import { useGT } from 'gt-next';
import { getProductMessages } from '../utils/productData';

function ProductCard({ product }) {
  const t = useGT();
  const messages = getProductMessages(t);
  
  return (
    <div>
      <h3>{product.name}</h3>
      <p>{messages.statusMessages[product.status]}</p>
      <span>{messages.categories.find(c => c.id === product.categoryId)?.name}</span>
    </div>
  );
}

Server Component with Metadata

import { getGT } from 'gt-next/server';

export async function generateMetadata({ params }) {
  const t = await getGT();
  
  return {
    title: t('Product Catalogue – Find What You Need'),
    description: t('Browse our extensive collection of high‑quality products'),
    openGraph: {
      title: t('Shop Our Products'),
      description: t('Discover amazing deals on top‑rated items')
    }
  };
}

export default async function ProductPage() {
  const t = await getGT();
  
  return (
    <div>
      <h1>{t('Featured Products')}</h1>
      <p>{t('Check out our latest and most popular items')}</p>
    </div>
  );
}

Common issues

Dynamic content at runtime

Strings must be known at build time—you can’t translate dynamic content:

// ❌ Dynamic content won't work
function MyComponent() {
  const [userMessage, setUserMessage] = useState('');
  const t = useGT();
  
  return <p>{t(userMessage)}</p>; // This will fail
}

// ✅ Use predefined strings
function MyComponent() {
  const [messageType, setMessageType] = useState('welcome');
  const t = useGT();
  
  const messages = {
    welcome: t('Welcome to our app!'),
    goodbye: t('Thanks for visiting!')
  };
  
  return <p>{messages[messageType]}</p>;
}

Hook Rule Violations

Follow the React Hooks rules when using useGT:

// ❌ Don't call hooks conditionally
function MyComponent({ showMessage }) {
  if (showMessage) {
    const t = useGT(); // Hook rule violation
    return <p>{t('Hello!')}</p>;
  }
  return null;
}

// ✅ Always call hooks at top level
function MyComponent({ showMessage }) {
  const t = useGT();
  
  if (showMessage) {
    return <p>{t('Hello!')}</p>;
  }
  return null;
}

Synchronous vs Asynchronous Confusion

Use the correct function for your component type:

// ❌ Wrong: useGT in async component
export default async function AsyncComponent() {
  const t = useGT(); // This won't work
  return <p>{t('Hello')}</p>;
}

// ✅ Correct: getGT in async component  
export default async function AsyncComponent() {
  const t = await getGT();
  return <p>{t('Hello')}</p>;
}

// ✅ Correct: useGT in synchronous component
export default function SyncComponent() {
  const t = useGT();
  return <p>{t('Hello')}</p>;
}

For genuinely dynamic content that requires translation at runtime, see the Dynamic Content Guide.

Next steps

How is this guide?

Strings