# react-native: Internationaliser une mini-boutique
URL: https://generaltranslation.com/fr/docs/react-native/tutorials/mini-shop.mdx
---
title: Internationaliser une mini-boutique
description: Un tutoriel pratique React Native pour internationaliser une boutique simple à l’aide des composants GT React Native, des Hooks et de chaînes de caractères partagées
---
`gt-react-native` est encore expérimental et peut ne pas fonctionner dans tous les projets.
Si vous rencontrez un problème, merci de nous le signaler en [ouvrant une issue sur GitHub](https://github.com/generaltranslation/gt/issues).
Créez une petite « mini-boutique » entièrement locale et traduite dans React Native — sans services externes, sans routage et sans framework UI autre qu’Expo. Vous utiliserez de bout en bout les fonctionnalités principales de GT React Native et verrez comment elles s’articulent dans une interface mobile simple et réaliste.
Prérequis : React Native (Expo), bases de JavaScript/TypeScript
Ce que vous allez créer
* Une « boutique » sur un seul écran avec une liste de produits et un panier simple en mémoire
* Un sélecteur de langue et des libellés de navigation partagés
* Des nombres, devises et pluriels correctement internationalisés
Liens utilisés dans ce tutoriel
* Provider : [``](/docs/react-native/api/components/gtprovider)
* Composants : [``](/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)
* Chaînes de caractères et chaînes partagées : [`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), [Branches conditionnelles](/docs/react-native/guides/branches), [Chaînes de caractères](/docs/react-native/guides/strings), [Stockage local des traductions](/docs/react-native/guides/local-tx), [Changer de langue](/docs/react-native/guides/languages)
***
## Installez et intégrez le provider à votre application
Installez les packages et encapsulez votre application dans le provider.
```bash
npm i gt-react-native
npm i --save-dev gt
```
```bash
yarn add gt-react-native
yarn add --dev gt
```
```bash
bun add gt-react-native
bun add --dev gt
```
```bash
pnpm add gt-react-native
pnpm add --save-dev gt
```
Facultatif : projet de départ (Expo)
Si vous partez de zéro, générez une application Expo, puis installez les packages GT :
```bash copy
npx create-expo-app mini-shop --template blank-typescript
cd mini-shop
npm i gt-react-native
npm i --save-dev gt
```
Ajoutez ensuite les fichiers indiqués dans les sections ci-dessous (par ex. `App.tsx`, `components/*`, `data.ts`, `nav.ts`).
Mettez en place une configuration minimale du provider.
```tsx title="App.tsx" copy
import { GTProvider } from 'gt-react-native';
import Shop from './Shop';
export default function App() {
return (
);
}
```
Vous pouvez ajouter un `gt.config.json` dès maintenant (utile plus tard pour la CI et le stockage local) :
```json title="gt.config.json" copy
{
"defaultLocale": "en",
"locales": ["es", "fr"]
}
```
### Clés API de développement
Vous pouvez suivre ce tutoriel sans clé (l’application affichera la langue par défaut). Pour voir les traductions en temps réel et tester le changement de langue en développement, ajoutez des clés de développement.
Pour en savoir plus, consultez [Production et développement](/docs/react-native/concepts/environments).
```bash title=".env" copy
EXPO_PUBLIC_GT_API_KEY="your-dev-api-key"
EXPO_PUBLIC_GT_PROJECT_ID="your-project-id"
```
* Tableau de bord : https://dash.generaltranslation.com/signup
* Ou via la CLI :
```bash copy
npx gt auth
```
***
## Données d’amorçage et structure de l’application
Nous allons coder en dur un petit tableau de produits et tout conserver côté client. Pas de serveur, pas de navigation.
```ts title="data.ts" copy
export type Product = {
id: string;
name: string;
description: string;
price: number;
currency: 'USD' | 'EUR';
inStock: boolean;
addedAt: string; // chaîne de caractères de date ISO
};
export const products: Product[] = [
{
id: 'p-1',
name: 'Wireless Headphones',
description: 'Noise-cancelling over-ear design with 30h battery',
price: 199.99,
currency: 'USD',
inStock: true,
addedAt: new Date().toISOString()
},
{
id: 'p-2',
name: 'Travel Mug',
description: 'Double-wall insulated stainless steel (12oz)',
price: 24.5,
currency: 'USD',
inStock: false,
addedAt: new Date().toISOString()
}
];
```
***
## Libellés de navigation partagés avec msg et useMessages
Utilisez [`msg`](/docs/react-native/api/strings/msg) pour marquer des chaînes de caractères partagées dans la configuration, puis décodez-les avec [`useMessages`](/docs/react-native/api/strings/use-messages) au moment du rendu.
```tsx title="nav.ts" copy
import { msg } from 'gt-react-native';
export const navItems = [
{ label: msg('Home'), id: 'home' },
{ label: msg('Products'), id: 'products' },
{ label: msg('Cart'), id: 'cart' }
];
```
```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 { navItems } from '../nav';
export default function Header() {
const m = useMessages();
return (
Mini Shop
{navItems.map(item => (
{m(item.label)}
))}
);
}
const styles = StyleSheet.create({
header: {
paddingVertical: 16,
paddingHorizontal: 12,
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 8,
},
nav: {
flexDirection: 'row',
gap: 12,
marginBottom: 8,
},
navItem: {
fontSize: 14,
color: '#555',
},
});
```
***
## Cartes produit avec T, variables, Branch et Currency
Utilisez [``](/docs/react-native/api/components/t) pour la traduction en JSX. Encapsulez le contenu dynamique dans des composants variables comme [``](/docs/react-native/api/components/var), [``](/docs/react-native/api/components/num), [``](/docs/react-native/api/components/currency) et [``](/docs/react-native/api/components/datetime). Gérez l’état du stock avec [``](/docs/react-native/api/components/branch).
```tsx title="components/ProductCard.tsx" copy
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { T, Var, Currency, DateTime, Branch } from 'gt-react-native';
import type { Product } from '../data';
export default function ProductCard({ product, onAdd }: { product: Product; onAdd: () => void }) {
return (
{product.name}
{product.description}
Price: {product.price}
Added: {product.addedAt}
In stock}
false={Out of stock}
/>
Add to cart
);
}
const styles = StyleSheet.create({
card: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
padding: 12,
marginBottom: 12,
},
name: {
fontSize: 18,
fontWeight: '600',
marginBottom: 4,
},
description: {
fontSize: 14,
color: '#666',
marginBottom: 8,
},
price: {
fontSize: 16,
marginBottom: 4,
},
date: {
fontSize: 12,
color: '#999',
marginBottom: 8,
},
inStock: {
color: 'green',
marginBottom: 8,
},
outOfStock: {
color: 'tomato',
marginBottom: 8,
},
button: {
backgroundColor: '#007AFF',
paddingVertical: 10,
borderRadius: 6,
alignItems: 'center',
},
buttonDisabled: {
backgroundColor: '#ccc',
},
buttonText: {
color: '#fff',
fontWeight: '600',
},
});
```
***
## Panier avec gestion du pluriel et totaux
Utilisez [``](/docs/react-native/api/components/plural) pour exprimer "X articles dans le panier" et [``](/docs/react-native/api/components/currency) pour les totaux. Combinez-les avec [``](/docs/react-native/api/components/t), [``](/docs/react-native/api/components/var) et [``](/docs/react-native/api/components/num).
```tsx title="components/Cart.tsx" copy
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { T, Plural, Var, Num, Currency } from 'gt-react-native';
import type { Product } from '../data';
export default function Cart({ items, onClear }: { items: Product[]; onClear: () => void }) {
const total = items.reduce((sum, p) => sum + p.price, 0);
const itemCount = items.length;
return (
Cart
Your cart is empty}
one={You have {itemCount} item}
other={You have {itemCount} items}
/>
{items.map((p) => (
{p.name} — {p.price}
))}
Total: {total}
Clear cart
);
}
const styles = StyleSheet.create({
container: {
borderTopWidth: 1,
borderTopColor: '#eee',
paddingTop: 16,
marginTop: 16,
},
heading: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 8,
},
empty: {
color: '#999',
marginBottom: 8,
},
item: {
fontSize: 14,
marginVertical: 4,
},
total: {
fontSize: 16,
fontWeight: '600',
marginTop: 8,
marginBottom: 12,
},
button: {
backgroundColor: '#FF3B30',
paddingVertical: 10,
borderRadius: 6,
alignItems: 'center',
},
buttonDisabled: {
backgroundColor: '#ccc',
},
buttonText: {
color: '#fff',
fontWeight: '600',
},
});
```
***
## Attributs et textes indicatifs avec `useGT`
Utilisez [`useGT`](/docs/react-native/api/strings/use-gt) pour traduire des chaînes de caractères simples, comme les textes indicatifs des champs de saisie et les libellés d’accessibilité.
```tsx title="components/Search.tsx" copy
import { TextInput, StyleSheet } from 'react-native';
import { useGT } from 'gt-react-native';
export default function Search({ onQuery }: { onQuery: (q: string) => void }) {
const gt = useGT();
return (
);
}
const styles = StyleSheet.create({
input: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
padding: 10,
fontSize: 16,
},
});
```
***
## Assemblez le tout
Une application à écran unique avec un panier en mémoire et un filtre de recherche simple.
```tsx title="Shop.tsx" copy
import { useMemo, useState } from 'react';
import { SafeAreaView, ScrollView, View, StyleSheet } from 'react-native';
import Header from './components/Header';
import Search from './components/Search';
import ProductCard from './components/ProductCard';
import Cart from './components/Cart';
import { products } from './data';
export default function Shop() {
const [query, setQuery] = useState('');
const [cart, setCart] = useState([]);
const filtered = useMemo(() => {
const q = query.toLowerCase();
return products.filter(p =>
p.name.toLowerCase().includes(q) || p.description.toLowerCase().includes(q)
);
}, [query]);
const items = products.filter(p => cart.includes(p.id));
return (
{filtered.map(p => (
setCart(c => (p.inStock ? [...new Set([...c, p.id])] : c))}
/>
))}
setCart([])}
/>
);
}
const styles = StyleSheet.create({
safe: {
flex: 1,
backgroundColor: '#fff',
},
scroll: {
padding: 16,
},
searchContainer: {
marginVertical: 12,
},
products: {
gap: 0,
},
});
```
***
## Exécuter en local
Démarrez le serveur de développement Expo :
```bash
npx expo start
```
Ouvrez ensuite l’application Expo Go sur votre téléphone, ou appuyez sur `i` pour le simulateur iOS / `a` pour l’émulateur Android.
***
## Ce que vous avez appris
* Traduire du JSX avec [``](/docs/react-native/api/components/t) et gérer le contenu dynamique à l’aide de [``](/docs/react-native/api/components/var), [``](/docs/react-native/api/components/num), [``](/docs/react-native/api/components/currency), [``](/docs/react-native/api/components/datetime)
* Exprimer du contenu conditionnel avec [``](/docs/react-native/api/components/branch) et les quantités avec [``](/docs/react-native/api/components/plural)
* Traduire des attributs avec [`useGT`](/docs/react-native/api/strings/use-gt)
* Partager des chaînes de caractères de navigation/configuration avec [`msg`](/docs/react-native/api/strings/msg) et les décoder avec [`useMessages`](/docs/react-native/api/strings/use-messages)
* Changer de langue avec [``](/docs/react-native/api/components/locale-selector)
## Étapes suivantes
* Découvrez : [Guide des variables](/docs/react-native/guides/variables), [Guide des branches conditionnelles](/docs/react-native/guides/branches), [Guide des chaînes de caractères](/docs/react-native/guides/strings), [Changer de langue](/docs/react-native/guides/languages)