Stringhe condivise
Come internazionalizzare stringhe utilizzate in più componenti e file
Le stringhe condivise sono valori di testo utilizzati in più punti dell’applicazione, come etichette di navigazione, messaggi dei moduli o dati di configurazione. Invece di duplicare la logica di traduzione ovunque, usa msg per contrassegnare le stringhe da tradurre e useMessages per decodificarle.
Il problema dei contenuti condivisi
Considera questa configurazione di navigazione utilizzata in tutta l’app:
// navData.ts
export const navData = [
{
label: 'Home',
description: 'La home page',
href: '/'
},
{
label: 'About',
description: 'Informazioni sull\'azienda',
href: '/about'
}
];Per internazionalizzare questo, in genere dovresti:
- Convertirlo in una funzione che accetti una funzione di traduzione
- Aggiornare ogni punto d’uso per chiamare la funzione con
t - Gestire la complessità in tutto il codebase
Questo comporta oneri di manutenzione e rende il codice più difficile da leggere. La funzione msg risolve il problema permettendoti di contrassegnare le stringhe per la traduzione inline e poi decodificarle quando necessario.
Guida rapida
Usa msg per contrassegnare le stringhe e useMessages per decodificarle:
// navData.ts - Contrassegna le stringhe per la traduzione
import { msg } from 'gt-next';
export const navData = [
{
label: msg('Home'),
description: msg('La pagina iniziale'),
href: '/'
},
{
label: msg('Chi siamo'),
description: msg('Informazioni sull\'azienda'),
href: '/about'
}
];// Utilizzo del componente - Decodifica stringhe marcate
import { useMessages } from 'gt-next';
import { navData } from './navData';
function Navigation() {
const m = useMessages();
return (
<nav>
{navData.map((item) => (
<a key={item.href} href={item.href} title={m(item.description)}>
{m(item.label)}
</a>
))}
</nav>
);
}Come funzionano le stringhe condivise
Il sistema delle stringhe condivise opera in due fasi:
- Fase di marcatura:
msgcontrassegna le stringhe con metadati di traduzione - Fase di decodifica:
useMessagesogetMessagesdecodificano e traducono le stringhe
// msg() codifica la stringa con i metadati
const encoded = msg('Hello, world!');
console.log(encoded); // "Hello, world!:eyIkX2hhc2giOiJkMjA3MDliZGExNjNlZmM2In0="
// useMessages() decodifica e traduce
const m = useMessages();
const translated = m(encoded); // "Hello, world!" nella lingua dell'utenteLe stringhe codificate da msg non possono essere utilizzate direttamente: devono essere decodificate con useMessages o getMessages.
Uso lato client vs lato server
Componenti client
Usa l’hook useMessages:
import { useMessages } from 'gt-next';
const encodedString = msg('Ciao, mondo!');
function MyComponent() {
const m = useMessages();
return <div>{m(encodedString)}</div>;
}Server Components
Usa la funzione getMessages:
import { getMessages } from 'gt-next/server';
const encodedString = msg('Ciao, mondo!');
async function MyServerComponent() {
const m = await getMessages();
return <div>{m(encodedString)}</div>;
}Recuperare le stringhe originali con decodeMsg
A volte è necessario accedere alla stringa originale senza traduzione, ad esempio per il logging, il debug o i confronti. Usa decodeMsg per estrarre il testo originale:
import { decodeMsg } from 'gt-next';
const encoded = msg('Hello, world!');
const original = decodeMsg(encoded); // "Hello, world!" (originale)
const translated = m(encoded); // "Hello, world!" (nella lingua dell'utente)
// Utile per il logging o il debugging
console.log('Stringa originale:', decodeMsg(encoded));
console.log('Stringa tradotta:', m(encoded));Casi d’uso di decodeMsg
- Sviluppo e debugging: registra le stringhe originali per il troubleshooting
- Gestione dei fallback: usa il testo originale quando la traduzione non è disponibile
- Confronto delle stringhe: confronta con valori originali noti
- Analytics: monitora l’utilizzo delle stringhe originali
// Esempio: Gestione del fallback
function getDisplayText(encodedStr) {
const m = useMessages();
try {
return m(encodedStr);
} catch (error) {
console.warn('Traduzione non riuscita, uso l\'originale:', decodeMsg(encodedStr));
return decodeMsg(encodedStr);
}
}Uso delle variabili
Per le stringhe con contenuto dinamico, usa segnaposto e passa le variabili:
// Contrassegna stringa con variabili
const items = 100;
export const pricing = [
{
name: 'Basic',
price: 100,
description: msg('Il piano Basic include {items} elementi', { items })
}
];// Uso nel componente
function PricingCard() {
const m = useMessages();
return (
<div>
<h3>{pricing[0].name}</h3>
<p>{m(pricing[0].description)}</p>
</div>
);
}Formato dei messaggi ICU
Per formattazioni avanzate, usa la sintassi ICU:
const count = 10;
const message = msg('Nel carrello {count, plural, =0 {non ci sono articoli} =1 {c\'è un articolo} other {ci sono {count} articoli}}', { count });Scopri di più sull’ICU Message Format nella documentazione di Unicode.
Esempi
Configurazione della navigazione
// config/navigation.ts
import { msg } from 'gt-next';
export const mainNav = [
{
label: msg('Home'),
href: '/',
icon: 'home'
},
{
label: msg('Prodotti'),
href: '/products',
icon: 'package'
},
{
label: msg('Chi siamo'),
href: '/about',
icon: 'info'
}
];
export const footerLinks = [
{
title: msg('Azienda'),
links: [
{ label: msg('Chi siamo'), href: '/about' },
{ label: msg('Lavora con noi'), href: '/careers' },
{ label: msg('Contatti'), href: '/contact' }
]
},
{
title: msg('Assistenza'),
links: [
{ label: msg('Centro assistenza'), href: '/help' },
{ label: msg('Documentazione'), href: '/docs' },
{ label: msg('Riferimenti API'), href: '/api' }
]
}
];// components/Navigation.tsx
import { useMessages } from 'gt-next';
import { mainNav } from '../config/navigation';
function Navigation() {
const m = useMessages();
return (
<nav>
{mainNav.map((item) => (
<a key={item.href} href={item.href}>
<Icon name={item.icon} />
{m(item.label)}
</a>
))}
</nav>
);
}Configurazione del modulo
// config/forms.ts
import { msg } from 'gt-next';
export const formMessages = {
placeholders: {
email: msg('Inserisci il tuo indirizzo email'),
password: msg('Inserisci la tua password'),
message: msg('Scrivi qui il tuo messaggio...')
},
actions: {
send: msg('Invia messaggio'),
save: msg('Salva le modifiche'),
cancel: msg('Annulla')
},
validation: {
required: msg('Questo campo è obbligatorio'),
email: msg('Inserisci un indirizzo email valido'),
minLength: msg('Deve contenere almeno {min} caratteri', { min: 8 }),
maxLength: msg('Non può superare {max} caratteri', { max: 100 })
},
success: {
saved: msg('Modifiche salvate correttamente'),
sent: msg('Messaggio inviato correttamente'),
updated: msg('Profilo aggiornato')
},
errors: {
network: msg('Errore di rete - riprova'),
server: msg('Errore del server - contatta l\'assistenza'),
timeout: msg('Tempo di richiesta scaduto - riprova')
}
};// components/ContactForm.tsx
import { useMessages } from 'gt-next';
import { formMessages } from '../config/forms';
function ContactForm() {
const m = useMessages();
const [errors, setErrors] = useState({});
return (
<form>
<input
type="email"
placeholder={m(formMessages.placeholders.email)}
required
/>
{errors.email && <span>{m(formMessages.validation.email)}</span>}
<button type="submit">
{m(formMessages.actions.send)}
</button>
</form>
);
}Generazione di contenuto dinamico
// utils/productData.ts
import { msg } from 'gt-next';
function mockProducts() {
return [
{ name: 'iPhone 15', company: 'Apple', category: 'Elettronica' },
{ name: 'Galaxy S24', company: 'Samsung', category: 'Elettronica' }
];
}
export function getProductData() {
const products = mockProducts();
return products.map(product => ({
...product,
description: msg('{name} è un prodotto di {category} di {company}', {
name: product.name,
category: product.category,
company: product.company
})
}));
}// components/ProductList.tsx
import { useMessages } from 'gt-next';
import { getProductData } from '../utils/productData';
function ProductList() {
const m = useMessages();
const products = getProductData();
return (
<div>
{products.map(product => (
<div key={product.name}>
<h3>{product.name}</h3>
<p>{m(product.description)}</p>
</div>
))}
</div>
);
}Problemi comuni
Utilizzo diretto di stringhe codificate
Non usare mai direttamente l’output di msg:
// ❌ Errato - stringa codificata utilizzata direttamente
const encoded = msg('Hello, world!');
return <div>{encoded}</div>; // Mostra la stringa codificata, non la traduzione
// ✅ Corretto - decodifica prima la stringa
const encoded = msg('Hello, world!');
const m = useMessages();
return <div>{m(encoded)}</div>; // Mostra la traduzione appropriataContenuto dinamico in msg()
Le stringhe devono essere note in fase di build:
// ❌ Errato - template literal dinamico
const name = 'John';
const message = msg(`Hello, ${name}`); // Errore in fase di build
// ✅ Corretto - utilizza variabili
const name = 'John';
const message = msg('Hello, {name}', { name });Dimenticare di decodificare
Ogni stringa msg deve essere decodificata:
// ❌ Decodifica mancante
const config = {
title: msg('Dashboard'),
subtitle: msg('Bentornato')
};
// Più avanti nel componente: decodifica dimenticata
return <h1>{config.title}</h1>; // Mostra la stringa codificata
// ✅ Corretto: decodifica all'uso
const m = useMessages();
return <h1>{m(config.title)}</h1>; // Mostra il titolo tradottoProssimi passaggi
- Guida ai dizionari - Organizza le traduzioni con dati strutturati
- Guida alle lingue - Configura le lingue supportate
- Riferimenti API:
- Funzione
msg - Hook
useMessages
- Funzione
Come valuti questa guida?