36
loading...
This website collects cookies to deliver better user experience
const rowData = [{food: "PORRIDGE"}, {food: "EGGS"}];
const TRANSLATIONS = {
'en-GB': { PORRIDGE: 'porridge', EGGS: 'eggs'},
'es-ES': { PORRIDGE: 'gachas de avena', EGGS: 'huevos'}
};
function translate(language, key){
return TRANSLATIONS[language][key];
}
type TranslationsType = Record<string, Record<string, string>>;
const TRANSLATIONS: TranslationsType = {
"en-GB": {...},
"es-ES": {...},
"de-DE": {
...
PORRIDGE: "Brei",
OMLETTE: "Omlette",
SANDWICH: "Sandwich",
SOUP: "Suppe",
PROTEINSHAKE: "Protein-Shake",
CHOCOLATEBAR: "Schokoriegel",
SAUSAGES: "Würstchen",
STEAK: "Steak",
LAMBCHOPS: "Lammkoteletts",
...
// Start of ag-Grid locale translations
selectAll: "(Wählen Sie Alle)",
searchOoo: "Suche...",
blanks: "(Leerzeichen)",
noMatches: "Keine Treffer",
...
}
getColumnDefs()
factory method in Columns.tsx <AgGridReact
localeText={TRANSLATIONS[props.language]}
...
/>
const translate = (key: string, language: string): string => {
return TRANSLATIONS[language][key];
};
TRANSLATIONS
object."TRANSLATIONS
object, we'll get the translated value via this little beauty.TRANSLATIONS
/translate()
route, such as date and price values.toLocaleDateString()
method which allows to translate a JavaScript date object in any format into any language!const DAY_OPTION: { weekday: string } = { weekday: "long" };
const DATE_OPTION: { year: string; month: string; day: string } = {
year: "numeric",
month: "long",
day: "numeric"
};
const translateDateTime = (
date: Date,
language: string,
options: {}
): string => {
return date.toLocaleDateString(language, options);
};
const translatePrice = (value: number, language: string): string => {
let currency = language === "en-GB" ? "GBP" : "EUR";
return value.toLocaleString(language, {
minimumFractionDigits: 2,
style: "currency",
currency: currency
});
};
Number.prototype.toLocaleString()
documentation. <AgGridReact
...
columnDefs={getColumnDefs(props.language)}
...
/>
const translateColumnFactory = (
colId: string,
field: string,
filterType: string,
language: string,
valueFormatter?: WithValueFormatter,
valueGetter?: WithValueGetter,
other?: object
) => {
let column = columnFactory(
colId,
field,
filterType,
language,
valueFormatter,
valueGetter
);
Object.assign(column, other);
return column;
};
const columnFactory = (
colId: string,
field: string,
filterType: string,
language: string,
valueFormatterFn?: WithValueFormatter,
valueGetterFn?: WithValueGetter
) => {
return {
colId,
field,
headerName: translate(colId.toUpperCase(), language),
filter: filterType,
...(valueFormatterFn == null
? undefined
: { valueFormatter: valueFormatterFn.valueFormatterFn(language) }),
...(valueGetterFn == null
? undefined
: { valueGetter: valueGetterFn.valueGetterFn(language) })
};
};
valueFormatter
or valueGetter
can only take one argument at runtime – to understand more about this check out documentation on valueFormatters and valueGetters. This means that there is no way to provide these functions with language as an argument, all they get is a params object via the grid. valueGetterFn()
& valueFormatterFn()
- these are the preparation steps. This becomes a clearer when we look at their interfaces, for example the withValueGetter
interface as shown below:interface WithValueGetter {
valueGetterFn(language: string): (params: ValueGetterParams) => string;
}
const TEXT_VALUEGETTER: WithValueGetter = {
valueGetterFn: (language) => (params) => {
let field = params.column.getColDef().field as string;
return translate(params.data[field], language);
}
};
translate()
method which gives us the localized value for the string.other?
arguments of each column. Notice how the price column has a filterParams
with a numberParser
and allowedCharPattern
?translateColumnFactory(
"price",
"price",
"agNumberColumnFilter",
language,
PRICE_VALUEFORMATTER,
undefined,
{
filterParams: {
filterOptions: ["equals", "lessThan", "greaterThan"],
buttons: ["apply", "reset"],
suppressAndOrCondition: true,
allowedCharPattern: "\\d\\,\\.",
numberParser: (value?: string) => {
if (value == null) {
return null;
}
let filterVal = value.replace(",", ".");
return Number(filterVal);
}
}
}
)
valueGetter
, filter inputs are directly compared with the getter's outputs. However, where formatters are used, another step needs to occur to prepare the filter input for comparison. Above we can see how when the European-style "," is used, it is translated into the English style "." for comparison. Thus, allowing us to filter for numbers with both styles of input. const [language, setLanguage] = useState<string>(LANGUAGE_OPTIONS.EN);
<span style={buttonSpanStyles}>
<label style={{ fontFamily: "Arial" }}>Translate to: </label>
<button
style={buttonStyles}
onClick={() => setLanguage(LANGUAGE_OPTIONS.EN)}
>
English
</button>
<button
style={buttonStyles}
onClick={() => setLanguage(LANGUAGE_OPTIONS.ES)}
>
Spanish
</button>
<Grid language={language} />
props.language
as a dependency. When the language changes, we want to destroy the grid. Immediately after, we want the grid to reappear. const [destroyed, setDestroyed] = useState(false);
useEffect(() => {
setDestroyed(true);
setTimeout(() => setDestroyed(false));
}, [props.language]);
return destroyed ? null : (
<div
id="myGrid"
style={{
height: "450px",
width: "95vw"
}}
className="ag-theme-alpine-dark"
>
<AgGridReact
...
...
null
for a moment before rendering a new grid with the newly chosen language being passed to a column-factory to get the correctly translated data and UI.