deps: i18next 10 -> 23, react-i18next 7 -> 14

Modernizes the whole i18n stack:
- 48 translate([], {wait:true}) / translate() HOCs -> withTranslation()
- react.wait:true -> react.useSuspense:false
- whitelist -> supportedLngs; added compatibilityJSON: 'v3' so our
  natural-language keys + v3 _plural layout keep working (custom
  separators ss/eth/dj preserved)
- backends: xhr -> i18next-http-backend (client), sync-fs ->
  i18next-fs-backend (server); dropped i18next-localstorage-cache
  (was enabled:false); languagedetector 2 -> 8
- ReSendEmail: <Interpolate> (removed in v10) -> <Trans values={{email}}/>,
  dropped the removed bare t export
- saveMissing handler signature (lngs, ns, key, fallbackValue)

Silences the per-component Translate/I18n legacy-context warnings.
Browser-verified es/en switch and <Trans> interpolation on /fires;
REST smoke byte-identical.
This commit is contained in:
vjrj 2026-07-18 06:28:41 +02:00
parent f1eae84e25
commit 12bdbe8fed
52 changed files with 226 additions and 553 deletions

View file

@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap';
/* import { Nav, NavDropdown } from 'react-bootstrap'; */
import { translate, Trans } from 'react-i18next';
import { withTranslation, Trans } from 'react-i18next';
import { testId } from '/imports/ui/components/Utils/TestUtils';
/*
@ -39,4 +39,4 @@ AuthenticatedNavigation.propTypes = {
name: PropTypes.string.isRequired
};
export default translate([], { wait: true })(withRouter(AuthenticatedNavigation));
export default withTranslation()(withRouter(AuthenticatedNavigation));

View file

@ -4,7 +4,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import './BetaRibbon.scss';
@ -30,4 +30,4 @@ BetaRibbon.propTypes = {
BetaRibbon.defaultProps = {
};
export default translate([], { wait: true })(BetaRibbon);
export default withTranslation()(BetaRibbon);

View file

@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import { Tracker } from 'meteor/tracker';
import { ReactiveVar } from 'meteor/reactive-var';
import { Button } from 'react-bootstrap';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { Bert } from 'meteor/themeteorchef:bert';
import './CenterInMyPosition.scss';
@ -63,4 +63,4 @@ CenterInMyPosition.propTypes = {
onlyIcon: PropTypes.bool
};
export default translate([], { wait: true })(CenterInMyPosition);
export default withTranslation()(CenterInMyPosition);

View file

@ -3,7 +3,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withTracker } from 'meteor/react-meteor-data';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { Meteor } from 'meteor/meteor';
import moment from 'moment';
import CommentsCollection from '/imports/api/Comments/Comments';
@ -149,4 +149,4 @@ const CommentsBoxContainer = withTracker(({ referenceId }) => {
};
})(CommentsBox);
export default translate([], { wait: true })(CommentsBoxContainer);
export default withTranslation()(CommentsBoxContainer);

View file

@ -2,7 +2,7 @@
/* eslint-disable import/no-absolute-path */
import React from 'react';
import PropTypes from 'prop-types';
import { Trans, translate } from 'react-i18next';
import { Trans, withTranslation } from 'react-i18next';
import Tooltip from 'rc-tooltip';
import Slider from 'rc-slider';
import 'rc-slider/assets/index.css';
@ -107,4 +107,4 @@ DistanceSlider.propTypes = {
onChange: PropTypes.func
};
export default translate([], { wait: true })(DistanceSlider);
export default withTranslation()(DistanceSlider);

View file

@ -5,7 +5,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { FormGroup, Button, FormControl } from 'react-bootstrap';
import { Bert } from 'meteor/themeteorchef:bert';
import { withTracker } from 'meteor/react-meteor-data';
@ -134,7 +134,7 @@ Feedback.propTypes = {
isHome: PropTypes.bool.isRequired
};
export default translate()(withTracker(props => ({
export default withTranslation()(withTracker(props => ({
emailAddress: props.emailAddress,
emailVerified: props.emailVerified,
isHome: isHome()

View file

@ -4,7 +4,7 @@ import React from 'react';
import { year } from '@cleverbeagle/dates';
import { Link } from 'react-router-dom';
import { Grid } from 'react-bootstrap';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { testId } from '/imports/ui/components/Utils/TestUtils';
import './Footer.scss';
@ -51,4 +51,4 @@ const Footer = (props) => {
Footer.propTypes = {};
export default translate([], { wait: true })(Footer);
export default withTranslation()(Footer);

View file

@ -5,7 +5,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTracker } from 'meteor/react-meteor-data';
import Chronos from '/imports/ui/components/Chronos/Chronos';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { dateLongFormat } from '/imports/api/Common/dates';
import './FromNow.scss';
@ -60,7 +60,7 @@ FromNow.defaultProps = {
* export default FromNowContainer;
* */
export default translate([], { wait: true })(withTracker((props) => {
export default withTranslation()(withTracker((props) => {
const whenDate = props.when;
return {
when: whenDate ? Chronos.moment(whenDate).fromNow() : null,

View file

@ -1,7 +1,7 @@
/* eslint-disable react/jsx-indent-props */
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import PlacesAutocomplete, { geocodeByAddress, getLatLng } from 'react-places-autocomplete';
import { FormGroup, ControlLabel, HelpBlock } from 'react-bootstrap';
import { Bert } from 'meteor/themeteorchef:bert';
@ -130,4 +130,4 @@ LocationAutocomplete.propTypes = {
i18n: PropTypes.object.isRequired
};
export default translate([], { wait: true })(LocationAutocomplete);
export default withTranslation()(LocationAutocomplete);

View file

@ -4,7 +4,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { GoogleLayer } from 'react-leaflet-google/lib/';
import Gkeys from '/imports/startup/client/Gkeys';
import { TileLayer, LayersControl } from 'react-leaflet';
@ -85,4 +85,4 @@ DefMapLayers.defaultProps = {
satellite: false
};
export default translate([], { wait: true })(DefMapLayers);
export default withTranslation()(DefMapLayers);

View file

@ -3,7 +3,7 @@ import React, { Component, Fragment } from 'react';
import { CircleMarker, Marker, Tooltip } from 'react-leaflet';
import PropTypes from 'prop-types';
import { fireIconS, fireIconM, fireIconL, nFireIcon, industryIcon, regIndustryIcon } from '/imports/ui/components/Maps/Icons';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { onMarkClick } from './MarkListeners';
import FirePopup from './FirePopup';
@ -80,4 +80,4 @@ FireIconMark.propTypes = {
t: PropTypes.func.isRequired
};
export default translate([], { wait: true })(FireIconMark);
export default withTranslation()(FireIconMark);

View file

@ -3,7 +3,7 @@
import React from 'react';
import { CircleMarker } from 'react-leaflet';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import FirePopup from './FirePopup';
/* Less acurate (1 pixel per fire) but faster */
@ -34,4 +34,4 @@ FirePixel.propTypes = {
t: PropTypes.func.isRequired
};
export default translate([], { wait: true })(FirePixel);
export default withTranslation()(FirePixel);

View file

@ -2,7 +2,7 @@
import React, { Fragment } from 'react';
import { Tooltip } from 'react-leaflet';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
const FirePopup = ({
lat,
@ -29,4 +29,4 @@ FirePopup.propTypes = {
t: PropTypes.func.isRequired
};
export default translate([], { wait: true })(FirePopup);
export default withTranslation()(FirePopup);

View file

@ -4,7 +4,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import FullscreenControl from 'react-leaflet-fullscreen';
import 'react-leaflet-fullscreen/dist/styles.css';
@ -25,4 +25,4 @@ FullScreenMap.propTypes = {
t: PropTypes.func.isRequired
};
export default translate([], { wait: true })(FullScreenMap);
export default withTranslation()(FullScreenMap);

View file

@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
import { Navbar } from 'react-bootstrap';
import { Link } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap';
import { Trans, translate } from 'react-i18next';
import { Trans, withTranslation } from 'react-i18next';
import { testId } from '/imports/ui/components/Utils/TestUtils';
/* import BetaRibbon from '../../components/BetaRibbon/BetaRibbon'; */
import PublicNavigation from '../PublicNavigation/PublicNavigation';
@ -71,4 +71,4 @@ Navigation.propTypes = {
authenticated: PropTypes.bool.isRequired
};
export default translate([], { wait: true })(Navigation);
export default withTranslation()(Navigation);

View file

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { Bert } from 'meteor/themeteorchef:bert';
import Icon from '../Icon/Icon';
import { translate, Trans } from 'react-i18next';
import { withTranslation, Trans } from 'react-i18next';
import { T9n } from 'meteor-accounts-t9n';
import './OAuthLoginButton.scss';
@ -60,4 +60,4 @@ OAuthLoginButton.propTypes = {
callback: PropTypes.func,
};
export default translate([], { wait: true })(OAuthLoginButton);
export default withTranslation()(OAuthLoginButton);

View file

@ -3,7 +3,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { LinkContainer } from 'react-router-bootstrap';
/* import { Nav } from 'react-bootstrap'; */
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { testId } from '/imports/ui/components/Utils/TestUtils';
/*
@ -32,4 +32,4 @@ PublicNavigation.propTypes = {
t: PropTypes.func.isRequired
};
export default translate([], { wait: true })(PublicNavigation);
export default withTranslation()(PublicNavigation);

View file

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Grid, Alert, Button } from 'react-bootstrap';
import { t, Trans, translate, Interpolate } from 'react-i18next';
import { Trans, withTranslation } from 'react-i18next';
import { T9n } from 'meteor-accounts-t9n';
const handleResendVerificationEmail = (emailAddress, t) => {
@ -16,7 +16,7 @@ const handleResendVerificationEmail = (emailAddress, t) => {
const ReSendEmail = props => (
<div>
{props.userId && !props.emailVerified ? <Alert className="verify-email text-center"><p><Interpolate i18nKey="verifyEmail" email={props.emailAddress}></Interpolate> <Button bsStyle="link" onClick={() => handleResendVerificationEmail(props.emailAddress, props.t)} href="#"><Trans parent="span">Reenviar email de verificación</Trans></Button></p></Alert> : ''}
{props.userId && !props.emailVerified ? <Alert className="verify-email text-center"><p><Trans i18nKey="verifyEmail" values={{ email: props.emailAddress }} /> <Button bsStyle="link" onClick={() => handleResendVerificationEmail(props.emailAddress, props.t)} href="#"><Trans parent="span">Reenviar email de verificación</Trans></Button></p></Alert> : ''}
</div>
);
@ -32,4 +32,4 @@ ReSendEmail.propTypes = {
emailVerified: PropTypes.bool.isRequired,
};
export default translate([], { wait: true })(ReSendEmail);
export default withTranslation()(ReSendEmail);

View file

@ -3,7 +3,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
/* import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker'; */
import Blaze from 'meteor/gadicc:blaze-react-component';
@ -28,7 +28,7 @@ Reconnect.propTypes = {
Reconnect.defaultProps = {
};
export default translate([], { wait: true })(Reconnect);
export default withTranslation()(Reconnect);
/*
if (!Meteor.isProduction) {

View file

@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { Map, Marker, CircleMarker, Circle, Tooltip } from 'react-leaflet';
import Leaflet from 'leaflet';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { withTracker } from 'meteor/react-meteor-data';
import update from 'immutability-helper';
import geolocation from '/imports/startup/client/geolocation';
@ -293,7 +293,7 @@ SelectionMap.propTypes = {
}))
};
export default translate([], { wait: true })(withTracker((props) => {
export default withTranslation()(withTracker((props) => {
const subscription = Meteor.subscribe('mysubscriptions');
// console.log(props.loadingSubs);
return {

View file

@ -3,7 +3,7 @@
/* eslint-disable import/no-absolute-path */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { withTracker } from 'meteor/react-meteor-data';
import { currentLocationHref } from '/imports/ui/components/Utils/location';
import {
@ -138,7 +138,7 @@ ShareIt.propTypes = {
ShareIt.defaultProps = {
};
export default translate([], { wait: true })(withTracker((props) => {
export default withTranslation()(withTracker((props) => {
const { title } = props;
return {
title

View file

@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { Bert } from 'meteor/themeteorchef:bert';
import FireSubscription from '/imports/ui/pages/FireSubscription/FireSubscription';
import { translate } from 'react-i18next';
import { withTranslation } from 'react-i18next';
import { isAnyMobile } from '/imports/ui/components/Utils/isMobile';
class SubscriptionEditor extends React.Component {
@ -89,4 +89,4 @@ SubscriptionEditor.propTypes = {
focusInput: PropTypes.bool
};
export default translate([], { wait: true })(SubscriptionEditor);
export default withTranslation()(SubscriptionEditor);