AG-Grid-React-Series-#70-Multi-Language-Support-in-AG-Grid
In today's globalized digital landscape, providing a user interface in multiple languages is no longer a luxury but a necessity for many applications. Delivering a localized experience significantly enhances user satisfaction, accessibility, and broadens your application's reach. For data-intensive applications leveraging AG-Grid in a React environment, implementing multi-language support (i18n) ensures that even the grid's intricate UI elements speak the user's language.
This installment of our AG-Grid React series will guide you through setting up and managing multi-language support within your AG-Grid instances, covering everything from the grid's internal text to dynamic column headers.
Why Localize Your AG-Grid?
- Enhanced User Experience: Users prefer interacting with applications in their native language, reducing cognitive load and improving usability.
- Global Reach: Break down language barriers and make your application accessible to a wider international audience.
- Accessibility: For diverse user bases, localization is a key aspect of making your application truly accessible.
- Professionalism: A localized application reflects a commitment to a diverse user base and a high level of polish.
AG-Grid's Built-in Localization Mechanism
AG-Grid provides a robust mechanism for localization through the gridOptions property called localeText. This property allows you to map internal AG-Grid text keys to translated strings, effectively changing the language of all grid-specific UI elements such as filter menus, context menus, column tool panels, and pagination controls.
When you use AG-Grid with React, you pass these gridOptions directly as props to your AgGridReact component.
Implementing Multi-Language Support in React
Step 1: Define Your Translation Objects
First, you need to create JavaScript objects where keys are AG-Grid's internal text identifiers and values are your translated strings. You'll typically have one object per language.
AG-Grid has a comprehensive list of locale text keys. You can find these in the official documentation, but here are some common ones to get you started:
// englishText.js
export const englishText = {
// Standard AG-Grid Text
loadingOoo: 'Loading...',
noRowsToShow: 'No Rows To Show',
// Filters
filterOoo: 'Filter...',
equals: 'Equals',
notEqual: 'Not equal',
contains: 'Contains',
notContains: 'Does not contain',
startsWith: 'Starts with',
endsWith: 'Ends with',
// ... many more filter options
applyFilter: 'Apply Filter',
resetFilter: 'Reset Filter',
clearFilter: 'Clear Filter',
// Column Menu
columns: 'Columns',
toolPanelColumns: 'Column Selection',
// Pagination
firstPage: 'First Page',
previousPage: 'Previous Page',
nextPage: 'Next Page',
lastPage: 'Last Page',
// ... and so on for all grid components
};
// spanishText.js
export const spanishText = {
// Standard AG-Grid Text
loadingOoo: 'Cargando...',
noRowsToShow: 'No hay filas para mostrar',
// Filters
filterOoo: 'Filtrar...',
equals: 'Igual a',
notEqual: 'Diferente de',
contains: 'Contiene',
notContains: 'No contiene',
startsWith: 'Empieza con',
endsWith: 'Termina con',
// ...
applyFilter: 'Aplicar Filtro',
resetFilter: 'Reiniciar Filtro',
clearFilter: 'Limpiar Filtro',
// Column Menu
columns: 'Columnas',
toolPanelColumns: 'Selección de Columnas',
// Pagination
firstPage: 'Primera Página',
previousPage: 'Página Anterior',
nextPage: 'Siguiente Página',
lastPage: 'Última Página',
// ...
};
Step 2: Apply localeText to AgGridReact
Once you have your translation objects, you pass the currently selected language's object to the localeText prop of your AgGridReact component.
Step 3: Dynamic Language Switching
To allow users to switch languages dynamically, you'll manage the current localeText object in your React component's state. When the language changes, you update this state, and React will re-render the AgGridReact component with the new translations.
Full Example: AG-Grid with Dynamic Language Switching
Let's put it all together in a single React component.
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css'; // Core grid CSS
import 'ag-grid-community/styles/ag-theme-alpine.css'; // Optional theme CSS
// Define your locale text objects
const englishText = {
loadingOoo: 'Loading...',
noRowsToShow: 'No Rows To Show',
filterOoo: 'Filter...',
equals: 'Equals',
notEqual: 'Not equal',
contains: 'Contains',
notContains: 'Does not contain',
startsWith: 'Starts with',
endsWith: 'Ends with',
applyFilter: 'Apply Filter',
resetFilter: 'Reset Filter',
clearFilter: 'Clear Filter',
columns: 'Columns',
toolPanelColumns: 'Column Selection',
firstPage: 'First Page',
previousPage: 'Previous Page',
nextPage: 'Next Page',
lastPage: 'Last Page',
// Add more as needed
};
const spanishText = {
loadingOoo: 'Cargando...',
noRowsToShow: 'No hay filas para mostrar',
filterOoo: 'Filtrar...',
equals: 'Igual a',
notEqual: 'Diferente de',
contains: 'Contiene',
notContains: 'No contiene',
startsWith: 'Empieza con',
endsWith: 'Termina con',
applyFilter: 'Aplicar Filtro',
resetFilter: 'Reiniciar Filtro',
clearFilter: 'Limpiar Filtro',
columns: 'Columnas',
toolPanelColumns: 'Selección de Columnas',
firstPage: 'Primera Página',
previousPage: 'Página Anterior',
nextPage: 'Siguiente Página',
lastPage: 'Última Página',
// Add more as needed
};
// Map locale codes to their text objects
const localeTextMap = {
en: englishText,
es: spanishText,
};
const GridLocalizationExample = () => {
const gridRef = useRef();
const [rowData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000 },
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxster', price: 72000 },
{ make: 'BMW', model: 'X5', price: 60000 },
]);
const [currentLocale, setCurrentLocale] = useState('en');
// Dynamically generate column definitions based on locale
const getColumnDefs = useCallback((locale) => {
const headerTranslations = {
en: {
make: 'Make',
model: 'Model',
price: 'Price',
},
es: {
make: 'Marca',
model: 'Modelo',
price: 'Precio',
},
};
const translations = headerTranslations[locale];
return [
{ field: 'make', headerName: translations.make, filter: true },
{ field: 'model', headerName: translations.model, filter: true },
{ field: 'price', headerName: translations.price, filter: true },
];
}, []);
const [columnDefs, setColumnDefs] = useState(getColumnDefs(currentLocale));
const onGridReady = useCallback((params) => {
// You can update column definitions here if needed after grid is ready
// params.api.setColumnDefs(getColumnDefs(currentLocale));
}, [currentLocale, getColumnDefs]);
// Update column definitions when currentLocale changes
useEffect(() => {
setColumnDefs(getColumnDefs(currentLocale));
}, [currentLocale, getColumnDefs]);
const switchLanguage = (langCode) => {
setCurrentLocale(langCode);
// AG-Grid automatically re-renders internal localeText.
// Column headers are handled by updating columnDefs in useEffect.
};
return (
<div style={{ width: '100%', height: '500px', padding: '20px' }}>
<h2>AG-Grid Multi-Language Example</h2>
<div style={{ marginBottom: '10px' }}>
<strong>Select Language:</strong>
<button onClick={() => switchLanguage('en')} style={{ marginLeft: '10px', padding: '5px 10px' }}>
English
</button>
<button onClick={() => switchLanguage('es')} style={{ marginLeft: '10px', padding: '5px 10px' }}>
Spanish
</button>
</div>
<div className="ag-theme-alpine" style={{ height: 400, width: '100%' }}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
localeText={localeTextMap[currentLocale]} // Pass the dynamic localeText object
defaultColDef={{
sortable: true,
filter: true,
resizable: true,
}}
onGridReady={onGridReady}
></AgGridReact>
</div>
</div>
);
};
export default GridLocalizationExample;
Translating Column Headers
While localeText handles the grid's internal UI text, it does not translate your custom content, such as column headers (defined by the headerName property in columnDefs).
To translate column headers, you need to update your columnDefs themselves. As shown in the example above:
- Maintain a separate object (e.g.,
headerTranslations) for your column header translations per language. - Create a function (e.g.,
getColumnDefs) that returns thecolumnDefsbased on the currently selected locale. - Use React's state (
useState) anduseEffecthook to update thecolumnDefswhenever thecurrentLocalechanges.
When the columnDefs state is updated, AG-Grid will automatically detect the changes and re-render the grid, including the localized headers.
Best Practices for AG-Grid Localization
- Externalize Translations: For larger applications, avoid embedding translation objects directly in your components. Store them in separate JSON files or dedicated modules, then import them as needed. This makes managing translations easier and cleaner.
-
Leverage i18n Libraries: For the rest of your React application's text (outside of AG-Grid's internal UI), use a dedicated internationalization library like
react-i18next. This provides robust features for handling pluralization, context, and interpolation, and you can integrate its current language state with your AG-Grid setup. -
Locale-Specific Formatting: Remember that localization isn't just about text. Dates, numbers, and currencies also need to be formatted according to the user's locale. AG-Grid offers Value Formatters that you can use with the native JavaScript
IntlAPI (Intl.NumberFormat,Intl.DateTimeFormat) or your i18n library's formatting utilities. -
Right-to-Left (RTL) Support: If you're targeting languages like Arabic or Hebrew, AG-Grid supports RTL layouts. You can enable this by setting the
enableRtlproperty on yourAgGridReactcomponent. - Handle Missing Translations: Decide how to handle keys that don't have a translation in a specific language. AG-Grid will typically fall back to its default English text, but your i18n library might offer more sophisticated fallback mechanisms.
Conclusion
Providing multi-language support in your AG-Grid React applications is a straightforward process thanks to AG-Grid's flexible localeText property and React's powerful state management. By combining static translation objects for the grid's internal elements and dynamically updating columnDefs for headers, you can offer a fully localized and user-friendly experience to a global audience. Embrace internationalization to make your data grids accessible and intuitive for everyone.