New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
en, en-US locales #3624
Comments
There is an moment.locale('fr')
"fr"
moment().format("LLLL")
"vendredi 25 novembre 2016 03:39"
moment.locale('en')
"en"
moment().format("LLLL")
"Friday, November 25, 2016 3:39 AM"
moment.locale('en-GB')
"en-gb"
moment().format("LLLL")
"Friday, 25 November 2016 03:40"
moment.locale('en-US')
"en"
moment().format("LLLL")
"Friday, November 25, 2016 3:40 AM" |
I don't buy it; consider the case where the locale is detected from the environment, and then a require dep path is constructed to load moment/locale/${detectedLocale}. If that variable is "en" or "en-us", then requirejs will fail to load a file(gets a 404). If it is detected as 'de', then the file will load. |
@eigood Moment's locale loader knows it already has English and doesn't try to load it from an external file. |
@icambron I don't think you are correct about walking down the tree when the user passes in 'en-US' as a locale. In fact, I am currently debugging through it and it is breaking because you are NOT walking down the tree. |
@steveccable Well, it does try to load it, just in case you had a more specific localization. When it fails, it tries just "en" and succeeds. I think the disconnect is just that somehow it failing to load "en-US" is breaking for you. Nothing is supposed to blow up here; it's just supposed to fail gracefully and move to the next option. So you'll have to tell me more about your environment: what, specifically, is going wrong? |
@icambron My environment is a React Native application using npm to control my dependencies, and I have been able to replicate the failure even in minimal sample applications. The problem is that in the loadLocale function, it attempts to require('./locale/' + name) where name is en-US, and that require fails. When that require fails in a release build, it causes the app to crash with a stack trace along the lines of the following:
Looking through the code, since getLocale sees that my key ('en-US') is not an array, it falls into loadLocale without ever trying to match 'en', which would only happen if it were to go into the chooseLocale function. EDIT: After looking a bit more closely at the chooseLocale function, it would still first try to choose 'en-US' and then fail the require before ever trying 'en', so the failed require leading to a crashing app would still occur even if this was an array. EDIT 2: Note that the require fails gracefully when in a debug (DEV) build and then it does fall down to using 'en'. I'm not sure why require is so much more explosive in PROD, but it is definitely breaking here in moment. EDIT 3: From the require js docs, "If you do not express the dependencies, you will likely get loading errors since RequireJS loads scripts asynchronously and out of order for speed." So the try/catch is unlikely to actually save us here, since try/catch only really helps with synchronous errors. |
So after working through it a bit, I have a (less than ideal) workaround. Basically, whenever my code tries to pass in a locale of 'en-US', I intercept it and pass in a locale of 'en' instead. Other locales are allowed to pass through unchanged. That said, I still think it is problematic that it can neither find en-US nor does it default to already having it, and you cannot include it specifically like you can with other locales to avoid the failure to find it when it is actually called upon. |
Right, that's what I'm saying. I'm trying to understand why a failing require call would be catastrophic. I wouldn't help to hardcode in knowledge of |
Working through it, it appears that React Native is not handling failed requires as gracefully as we might like. You are correct that it has nothing to do with en being a special case, and the only reason it seemed like it was special was because there was no way to prevent the en-US require from failing (since we can't import it directly like with other locales). As mentioned in the later edit, the try/catch doesnt work because it fails asynchronously. |
Oh, I missed that edit. That was going to be my guess too. |
@steveccable
I solved it with:
Maybe it helps |
The workaround of sanitising the locale input is ok, but it's really scary to know that a react native require() can fail asynchronously in any place and there is no way to catch that. Also, if i send a non-existing locale or a random string (say 'blah-Blah') that means the app crashes and i can't handle the error anywhere. So i have to be defensively checking around that nobody triggers this bug. |
I got problems after version 2.19.2 here's what changed with that release 29afed6...328d51e the function updateLocale started using loadLocale internally which in turn use require with a dynamic string Line 1845 in fea48bb
I guess this fails in react native cause there you can't require files dynamically by variable facebook/react-native#6391 In my specific case, I'm importing the en-gb file so it should be found in |
not sure that RN is a priority or not, but moment for RN will be broken for months.
|
For RN, I got it working in release mode by stripping to the first part of the locale (probably what moment does behind the screens when it fails to load the "xx-XX" locale). In the following snippet,
|
This is weird behavior. https://stackoverflow.com/a/47260841/175825 you need to import a specific locale for ecosystem to be able to consume them. Because of this magic, I can't get react-big-calendar to display dates like I could open an issue with react-big-calendar, but what about the next lib I come across that's expecting a specific locale? And the next one? Just add in |
It will not solve the problem, there are languages like Spanish ( |
For anyone who's still looking for a solution, this may help mitigate the issue (with the exception of a few edge cases) but won't fix the root issue of RN causing a crash during the try-catch import moment from 'moment/min/moment-with-locales.min.js';
// locale is the locale detected by react-native-device-info
// ts is the time
export const formatTime = (locale, ts) => {
const m = moment.utc(ts);
locale = chooseMomentLocale(locale);
m.locale(locale);
// other logic to determine whether to show the time as "9:43 pm", "yesterday", or "7/8/2018"
return formattedTime;
}
/**
* Checks if the device locale is available in moment and returns the locale to be loaded
* @param {string} locale locale to be checked
* @return {string} locale to be loaded by moment
*/
const chooseMomentLocale = (locale) => {
// make the locale lower case
// will fix crashes caused by "en-GB" (instead of "en-gb") not being found
locale = locale.toLowerCase();
if (moment.locales().includes(locale)) { // check if the locale is included in the array returned by `locales()` which (in this case) tells us which locales moment will support
return locale;
} else if (moment.locales().includes(locale.substring(0, 2))) {
// check if the first two letters of the locale are included in the array returned by `locales()` which (in this case) tells us which locales moment will support
// will fixes crashes caused by "en-US" not being found, as we'll tell moment to load "en" instead
return locale.substring(0, 2);
}
// use "en-gb" (the default language and locale for my app) as a fallback if we can't find any other locale
return 'en-gb';
}; |
I also experienced this issue using React Native and was able to avoid it by including all locales alongside Moment, i.e.
(Alternatively, |
This is a super annoying issue. Isn't the whole point of locales that you yon't even have to think about it, and certainly not be hardcoding 'en-US' into your code just because YOU are in US? I don't understand why when requesting a locale of 'en-US' it can't just take it. Causes people no end of headaches. I solved this problem a year ago but completely forgot how, then I have to start all over. (I'm using a date picker in Angular and just putting the minimum implementation in blows up with this error). I'm getting this in Angular trying to use the datetime picker. If I set the LOCALE to something like en-GB it works fine but without specifying anything I get this. I wish I could figure out the proper way to fix this |
This solution works for me, using
|
I am still experimenting this issue running the version "moment": "^2.22.2", |
I'll chime in on this issue.
|
I also had this error in react-native on production after making a nice development built that works perfectly. function parseLocaleForMoment (language) {
if (language.indexOf('-') === -1) return language
else return language.substr(0, language.indexOf('-'))
} |
Looks like RN sucks with moment so much that it's easier to just write a native formatter. Probably just one line of code, bullet proof to work. |
Ended up fixing it like this:
|
with react native @tapz sadly this seems to work on Android but on iOS sadly :/ I am having some trouble with |
That might be because zh and a few other locales are formatted differently to differentiate between Simplified and Traditional. See https://gist.github.com/jacobbubu/1836273 |
@rajivshah3 indeed I was having |
Same problem, in RN production mode only. This seems to work fine for me. import 'moment/locale/fr';
import 'moment/locale/es';
import 'moment/locale/de';
import 'moment/locale/en-gb';
import 'moment/locale/es-us';
const toMomentLocale = locale => {
let momentLocale = locale;
momentLocale = momentLocale.replace('_', '-').toLowerCase();
momentLocale = ['en-gb', 'en-us'].includes(locale)
? momentLocale
: momentLocale.split('-')[0];
return momentLocale;
}; As long as the data is imported (or |
This is genuinely ridiculous. Stripping out the
My temporary (and utterly batshit) workaround for React Native is this: const locale = 'zh-cn'; // or en-US etc
const languageCode = moment.locale(locale.indexOf("-") === -1 ? locale : locale.substr(0, locale.indexOf('-'))); // now 'zh', 'en' etc. Thanks @adesmet
let momentJsLocale;
switch(languageCode.toLowerCase()) {
case 'zh':
// No 'zh' locale exists in MomentJS. App will crash in production if used.
momentJsLocale = 'zh-cn';
break;
case 'pa':
momentJsLocale = 'pa-in';
break;
case 'hy':
momentJsLocale = 'hy-am';
break;
default:
momentJsLocale = languageCode.toLowerCase();
}
moment.locale(momentJsLocale); |
@adammcarth Hi, do we have any news about moment locales fix for RN? |
This just crashed on a release build right now using |
I get a similar problem problem as; @simeyla . When I added Luxon together with timepicker issues are popping up and they appear to be related to the 'en-US' locale.
Another problem with handling 'en-US' or other valid locales with exceptions is when you are debugging and ask debugger to brake on exceptions, you get stuck on this one repeatedly. There should be better and simpler way especially for such a large locale as the 'en-US'. |
I modified the solution from @slorber to be more robust. This reformats an incoming locale (e.g. "zh_CN" to "zh-cn") and checks if it's supported by your moment installation, falling back to the country, then falling back to en-us. const toMomentLocale = (locale) => {
let newLocale = locale.replace('_', '-').toLowerCase();
let tryLocales = [newLocale, newLocale.split('-')[0]];
for (let i = 0; i < tryLocales.length; i++) {
if (moment.locales().indexOf(tryLocales[i]) >= 0) return tryLocales[i];
}
return 'en-us';
};
// use it like this:
let m = moment();
m.locale(toMomentLocale('zh_CN')).format('LLL'); // "2019年12月11日上午9点33分" -- used "zh-cn"
moment.locale(toMomentLocale('ja_JP'));
moment().format('LLL') // 2019年12月11日 09:34 -- falls back to "ja" |
Same problem, in RN production IOS mode only. This seems to work fine for me. import moment from "moment"; |
Spent quite some time debugging this, thank you @jorodriguez for this |
This is still an issue 😢 |
Hi guys, I have created a tiny package for you -> https://github.com/tonix-tuft/moment-utl
You can use the following to determine all the supported locales of moment without the need to load them in advance: import { allSupportedLocales, allSupportedLocalesMap } from "moment-utl";
const locales = allSupportedLocales(); // As an array: ["af", "ar", "ar-dz", "ar-kw", "ar-ly", "ar-ma", "ar-sa", "ar-tn", "az", "be", "bg", ..., "en", ..., "zh-tw"]
const localesMap = allSupportedLocalesMap(); // As an object: { "af": 1, "ar": 2, "ar-dz": 3, "ar-kw": 4, "ar-ly": 5, "ar-ma": 6, "ar-sa": 7, "ar-tn": 8, "az": 9, "be": 10, ..., "en": 27, "zh-tw": 128 };
However, as You can use it with the
When using this script, just make sure to run it before you bundle your code with Rollup or Webpack (whichever you use), so it will generate an up-to-date locales array and object before your bundler comes across them and adds them to your final bundle. I hope this helps! |
In reply to @adammcarth, please check my answer here: tonix-tuft/moment-utl#1 (comment) |
This issue has haunted the guys at Odoo and the suggested fix was to create the en-us file manually. Sigh. What I don't understand is why moment tries loading the en-us file if, as told some comments above, the loader should know that it already has "en" and not dynamically import it. Anyway it's still a nightmare for RN users. The worst part is that the issue only occurs in production builds. Having a hidden default is a package of surprises... |
I'm going to get 👎 for this but my solution was swapping Just sharing what I did for people who might wanna consider this. |
I used |
Still a problem |
If you are using React Native (RN) then in release mode of the app |
We were having this issue as well when doing
Here is our fix with patch-package
diff --git a/node_modules/moment/min/moment-with-locales.js b/node_modules/moment/min/moment-with-locales.js
index 4e0b8d9..8e4787d 100644
--- a/node_modules/moment/min/moment-with-locales.js
+++ b/node_modules/moment/min/moment-with-locales.js
@@ -2071,8 +2071,7 @@
}
function loadLocale(name) {
- var oldLocale = null,
- aliasedRequire;
+ var oldLocale = null;
// TODO: Find a better way to register and load all the locales in Node
if (
locales[name] === undefined &&
@@ -2082,8 +2081,7 @@
) {
try {
oldLocale = globalLocale._abbr;
- aliasedRequire = require;
- aliasedRequire('./locale/' + name);
+ require('./locale/' + name);
getSetGlobalLocale(oldLocale);
} catch (e) {
// mark as not found to avoid repeating expensive file require call causing high CPU
For some reason the |
Found the solution here
|
In our project we using 2 languages (es, en) to translate days and month. I just swap 'en' to 'en-au' since it's a same names as in 'en-us', and it's work for me. import 'moment/locale/es' import 'moment/locale/en-au' |
Just a question:
Why are there no 'en', 'en-US' locales?
I understand they have been taken as the 'default' value, and so, if that's what you want, you don't need to use locale to start with.
But, imagine you have the typical combo where the user can choose the locale.
And you are calling moment.locale() with the current value of that.
With the current situation, you have to special case the en/en-US case, which seems like a bit awkward to me.
Thx for your great work. Keep on pushing!
The text was updated successfully, but these errors were encountered: