react-native-calendar-strip icon indicating copy to clipboard operation
react-native-calendar-strip copied to clipboard

Use locales crash the app on start in release

Open rdewolff opened this issue 5 years ago • 7 comments

Am having issues to configure the lib with 3 languages: en, fr and de.

I have found some issues related to the problem, but none worked for me. Some related issues include #89 #110 & #141.

For me the following elements need clarification:

  • The locale.name uses fr or en. Should'nt we use a full language and region code like fr-ch or en-uk? This seems to have been discussed on moment.

  • The locale.name seems to sometimes require just a language, but sometimes a region too. Depending on moment.js implementation. See node_modules/moment/locale/*.js for a list.

  • The locale.config object : why do we need to pass this as we still import the locale file? Why, if I specify the whole locale.config file as a copy of the moment lib, I still require moment to be imported?

While digging for solutions, I have found none that worked. Seeing the amount of issues are related to localization, there seems to be a lack of documentation and maybe some refactoring is required.

My current issue

Am just trying to set that up properly for the 3 languages stated above. I have tried many variants, but based on what I have read in the readme and in the related issues, I should do the following:

  1. import the moment libs
import 'moment'
# required ? import 'moment/min/locales'
import 'moment/locale/en'
import 'moment/locale/de'
import 'moment/locale/fr'

Use component as follow:

<CalendarStrip
          locale={{name: 'fr', config: 
months: 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split(
            '_'
        ),
        monthsShort: 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split(
            '_'
        ),
        monthsRegex: monthsRegex,
        monthsShortRegex: monthsRegex,
        monthsStrictRegex: monthsStrictRegex,
        monthsShortStrictRegex: monthsShortStrictRegex,
        monthsParse: monthsParse,
        longMonthsParse: monthsParse,
        shortMonthsParse: monthsParse,
        weekdays: 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
        weekdaysShort: 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
        weekdaysMin: 'di_lu_ma_me_je_ve_sa'.split('_'),
        weekdaysParseExact: true,
        longDateFormat: {
            LT: 'HH:mm',
            LTS: 'HH:mm:ss',
            L: 'DD/MM/YYYY',
            LL: 'D MMMM YYYY',
            LLL: 'D MMMM YYYY HH:mm',
            LLLL: 'dddd D MMMM YYYY HH:mm',
        },
        calendar: {
            sameDay: '[Aujourd’hui à] LT',
            nextDay: '[Demain à] LT',
            nextWeek: 'dddd [à] LT',
            lastDay: '[Hier à] LT',
            lastWeek: 'dddd [dernier à] LT',
            sameElse: 'L',
        },
        relativeTime: {
            future: 'dans %s',
            past: 'il y a %s',
            s: 'quelques secondes',
            ss: '%d secondes',
            m: 'une minute',
            mm: '%d minutes',
            h: 'une heure',
            hh: '%d heures',
            d: 'un jour',
            dd: '%d jours',
            w: 'une semaine',
            ww: '%d semaines',
            M: 'un mois',
            MM: '%d mois',
            y: 'un an',
            yy: '%d ans',
        },
        dayOfMonthOrdinalParse: /\d{1,2}(er|)/,
        ordinal: function (number, period) {
            switch (period) {
                // TODO: Return 'e' when day of month > 1. Move this case inside
                // block for masculine words below.
                // See https://github.com/moment/moment/issues/3375
                case 'D':
                    return number + (number === 1 ? 'er' : '');

                // Words with masculine grammatical gender: mois, trimestre, jour
                default:
                case 'M':
                case 'Q':
                case 'DDD':
                case 'd':
                    return number + (number === 1 ? 'er' : 'e');

                // Words with feminine grammatical gender: semaine
                case 'w':
                case 'W':
                    return number + (number === 1 ? 're' : 'e');
            }
        },
        week: {
            dow: 1, // Monday is the first day of the week.
            doy: 4, // The week that contains Jan 4th is the first week of the year.
        }, }}
...

That does not work and crash on app start on release.

Hypothese

Couldn't be the import something like:

import 'moment'
import 'moment/min/locales'
import localeEnGb from 'moment/locale/en-gb'
import localeDeCh from 'moment/locale/de-ch'
import localeFrCh from 'moment/locale/fr-ch'

Then the setup of the component like:

<CalendarStrip
          locale={{name: 'fr-ch', config: localeFrCh }}
...

Wouldn't that be cleaner and better developer experience?

Who can help me? What can I do to fix this?

Thanks for your help and input!

rdewolff avatar Oct 17 '20 14:10 rdewolff

Additional info on StackOverflow : https://stackoverflow.com/questions/49637158/react-native-release-crash-because-of-unkown-module-momentjs-locale

rdewolff avatar Oct 18 '20 09:10 rdewolff

react-native-calendar-strip relies on Moment's localization features. You will need to follow Moment's requirements.

Here's a boilerplate setup: https://github.com/BugiDev/react-native-calendar-strip#localization

The answer to the SO you linked also mentions calling Moment's locale() method e.g. moment().locale('fr');. Your app would need to call that whenever the user changes languages. The locale prop passed to RNCS will also need to change to match.

peacechen avatar Oct 18 '20 15:10 peacechen

Here's what I have in my app.js pertaining to localization:

import moment from "moment"; import "moment/locale/ja"; import "moment/locale/en";

let appLocale = NativeModules.SettingsManager.settings.AppleLocale || NativeModules.SettingsManager.settings.AppleLanguages[0];

// remove country portion of locale if (appLocale.indexOf("") > 0) appLocale = appLocale.split("")[0];

console.log("appLocale: " + appLocale);

moment.locale(appLocale); LocalizationConfig(appLocale)

In app.js I also have the import for moment and the specific country codes as above. The localization config will change the locale object depending on whether english or Japanese is the language. As I've said this works great in debug mode in the simulator but no luck in production.

Rianu avatar Jul 08 '21 13:07 Rianu

There's a risk that NativeModules.SettingsManager.settings.AppleLocale and/or AppleLanguages is a value other than ja or en. As a test, hard-code your app to moment.locale('ja') for the production build.

peacechen avatar Jul 08 '21 13:07 peacechen

I didn't mean to reply to this issue, sorry. I went back to my main issue. Yes I did hardcode "ja" into there for testing (in production build) since I'm not in Japan and can't get that locale unless I hardcode.

I followed the instructions and something must be wrong that we can't troubleshoot. I may have to leave it english.

Rianu avatar Jul 08 '21 14:07 Rianu

I have the similar crash where moment complain that the specified locale passed to the calendar strip prop is not loaded/configured. It turns out that I have 2 different versions of moment, one installed in node_modules/moment and the other installed in node_modules/react-native-calendar-strip/node_modules/moment.

Because of this, I got the following behaviours:

  • My app moment configured with our locale is not reflected on RN calendar strip because the library is using its own version of moment which still uses the default locale.
  • In development mode, passing locale via locale prop does not change the localization inside RN calendar strip because the specified locale is not loaded/configured for the RN calendar strip's moment.
  • In production mode, passing locale via locale prop results in a crash because the specified locale is not loaded/configured.

The temporary workaround

  • Specify resolutions in package.json:
  "resolutions": {
    "moment": "^2.29.0"
  }
  • Ensure that node_modules/react-native-calendar-strip/node_modules/moment does not exist after running yarn install.
  • After that, we can configure the locale and use RN calendar strip without passing locale prop.
import moment from 'moment'
import 'moment/locale/vi'

moment.locale('vi')

The permanent fix

moment should be specified as peer dependency inside the library's package.json.

Looooong avatar May 12 '22 17:05 Looooong

This is what I tried: import 'react-native-calendar-strip'; import 'react-native-calendar-strip/node_modules/moment/locale/vi';

trongtv147 avatar Jul 26 '22 00:07 trongtv147