就一个问题:
为什么没有“ en”,“ en-US”语言环境?
我知道它们已被视为“默认”值,因此,如果您要这样做,则无需使用语言环境作为开始。
但是,假设您有一个典型的组合,用户可以在其中选择区域设置。
然后,您使用当前值调用moment.locale()。
在当前情况下,您必须对en / en-US案例进行特殊处理,这对我来说似乎有点尴尬。
感谢您的出色工作。 继续努力!
有en
语言环境,只是没有单独的文件。 moment().locale()
和moment.locale()
非常接受它:
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"
en-US
也可以使用,因为我们步行搜索不太明确的匹配项,并且en
语言环境为美国英语:
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"
我不买考虑从环境中检测到语言环境的情况,然后构造require dep路径以加载一下moment / locale / $ {detectedLocale}。 如果该变量是“ en”或“ en-us”,则requirejs将无法加载文件(获取404)。 如果检测到为“ de”,则将加载文件。
@eigood Moment的语言环境加载器知道它已经具有英语,并且不会尝试从外部文件加载它。
@icambron我不认为您在用户通过“ en-US”作为语言环境时走下树是不正确的。 实际上,我目前正在调试它,但由于您没有沿着树走,它正在中断。
我的用例是我正在调用moment.utc(myDate,myFormat,locale,true),其中locale只是单个字符串“ en-US”。 由于无法导入该字符串(因为没有用于该字符串的文件),但是它不是数组,因此它将尝试要求使用语言环境,然后在生产环境中中断。
在我看来,真正的最佳行为是在默认情况下将en-US包含在默认显示的语言环境列表中(目前不存在,仅靠en本身)。
@steveccable好吧,它确实会尝试加载它,以防万一您有更具体的本地化。 当它失败时,它尝试“ en”并成功。 我认为断开连接只是因为某种原因而无法加载“ en-US”对您来说很困难。 这里什么都不会炸毁。 它只是应该正常失败,然后转到下一个选项。 因此,您必须向我详细介绍您的环境:特别是哪里出了问题?
@icambron我的环境是一个使用npm来控制我的依赖关系的React Native应用程序,即使在最小的示例应用程序中,我也能够复制故障。 问题在于,在loadLocale函数中,它尝试在名称为en-US的require('./ locale /'+ name)的情况下失败。 如果该要求在发行版本中失败,则将导致应用程序崩溃,并带有如下所示的堆栈跟踪:
E/ReactNativeJS: Requiring unknown module "./locale/en-us".
E/AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
Process: com.myApp, PID: 30054
com.facebook.react.common.JavascriptException: Requiring unknown module "./locale/en-US"., stack:
o<strong i="7">@2</strong>:742
n<strong i="8">@2</strong>:426
i<strong i="9">@2</strong>:278
t<strong i="10">@2</strong>:210
Xe<strong i="11">@648</strong>:16702
nt<strong i="12">@648</strong>:17804
gt<strong i="13">@648</strong>:22583
yt<strong i="14">@648</strong>:22460
wt<strong i="15">@648</strong>:23200
c<strong i="16">@648</strong>:1112
parse<strong i="17">@645</strong>:1536
render<strong i="18">@643</strong>:2923
_renderValidatedComponentWithoutOwnerOrContext<strong i="19">@141</strong>:7295
_renderValidatedComponent<strong i="20">@141</strong>:7462
performInitialMount<strong i="21">@141</strong>:3012
mountComponent<strong i="22">@141</strong>:2056
mountComponent<strong i="23">@132</strong>:205
performInitialMount<strong i="24">@141</strong>:3162
mountComponent<strong i="25">@141</strong>:2056
mountComponent<strong i="26">@132</strong>:205
performInitialMount<strong i="27">@141</strong>:3162
mountComponent<strong i="28">@141</strong>:2056
mountComponent<strong i="29">@132</strong>:205
查看代码,因为getLocale看到我的键(“ en-US”)不是数组,所以它不尝试匹配“ en”就落入loadLocale,只有在进入chooseLocale函数时才会发生。
编辑:在更仔细地查看了selectLocale函数之后,它仍然会首先尝试选择'en-US',然后在尝试'en'之前失败需求,因此失败的需求甚至导致崩溃的应用程序仍然会发生如果这是一个数组。
同样令人奇怪的是,它断开的位置位于try / catch内,但仍然会导致崩溃。 这实际上是这里真正令人困惑的事情。
编辑2:请注意,在进行调试(__DEV__)生成时,require会优雅地失败,然后确实会下降为使用'en'。 我不确定为什么__PROD__中的require如此具有爆炸性,但是肯定会在此中断。
编辑3:从require js文档中,“如果不表达依赖关系,由于RequireJS异步加载脚本并且速度混乱,您可能会获得加载错误。” 因此,try / catch不太可能真正将我们保存在这里,因为try / catch只能真正帮助解决同步错误。
因此,在经过一些工作之后,我有一个(不太理想的)解决方法。 基本上,每当我的代码尝试传递“ en-US”的语言环境时,我都将其拦截并传递“ en”的语言环境。 允许其他语言环境不变地通过。
就是说,我仍然认为它既找不到美国也不存在默认问题,并且不能像在其他语言环境中那样专门包含它,以避免在实际调用它时找不到它在。
@steveccable
同样令人奇怪的是,它断开的位置位于try / catch内,但仍然会导致崩溃。 这实际上是这里真正令人困惑的事情。
是的,这就是我的意思。 我试图理解为什么失败的需求呼叫会带来灾难性的后果。 我不愿意对en-US
知识进行硬编码; 在其他任何后备情况下,我们仍然会有类似的失败。 即,这与en
是特例无关,但与回退过程无关,在您的环境中根本无法工作。
通过它的工作,React Native似乎并没有像我们所希望的那样优雅地处理失败的需求。 没错,这与en的特殊情况无关,而且看起来特殊的唯一原因是因为没有办法防止en-US要求失败(因为我们无法直接导入它)就像其他语言环境一样)。 如后面的编辑中所述,try / catch不起作用,因为它异步失败。
就目前而言,我上面提到的解决方法只是出于我的目的清理“ en-US”语言环境。
尝试/捕获不起作用,因为它异步失败
哦,我错过了那个编辑。 这也是我的猜测。
@steveccable
不确定您是否仍然遇到问题,但是与发布版本完全相同的崩溃(尽管在法国语言环境中)使我花了一天的时间😢
E/ReactNativeJS: Requiring unknown module "./locale/fr".
(...)
我用以下方法解决了它:
import 'moment/locale/fr';
也许有帮助
清理语言环境输入的变通办法是可以的,但是要知道一个反应本机的require()可能在任何地方异步失败,而且没有办法捕获它,真是令人恐惧。 另外,如果我发送不存在的语言环境或随机字符串(例如'blah-Blah'),这意味着应用程序崩溃了,并且我无法在任何地方处理错误。 因此,我必须进行防御性检查,以确保没有人触发此错误。
我在2.19.2版本之后遇到了问题,以下是该版本https://github.com/moment/moment/compare/29afed6...328d51e所做的更改,函数updateLocale在内部开始使用loadLocale,而后者又需要使用动态字符串https ://github.com/moment/moment/blob/fea48bb69eda8c0459915d6aa66a910a4d43a55b/moment.js#L1845
我猜这无法响应本机,因为您无法通过变量https://github.com/facebook/react-native/issues/6391动态要求文件
在我的特定情况下,我正在导入en-gb文件,因此应在调用moment.locale时在locales[name]
找到它。 我不知道为什么会失败。
不确定RN是否优先,但是RN的时间将中断数月。
有了所有这些,看来facebook#69是解除所有人封锁的最有效的解决方案。 我将与@jeanlauliac交谈,我们将看看是否可以在星期一合并它。
仅提供一些背景信息:我们不支持动态依赖项的原因有多种。 首先,当动态需要模块时,静态分析会中断。 其次,当使用动态需求时,您正在寻找的实际模块可能不可用。 这可能会导致生产中出现重大问题,从而阻止用户使用我们的应用程序,例如我们可能破坏Facebook。 过去我们遇到过这样的问题,很难解决。 Metro专为防止他人从事会给用户带来痛苦的事情而采取自以为是的态度。
最后,我们了解到该开源仓库目前状况不佳。 好消息是,FB上没有更多的人在Metro上工作,我们在商店中进行了许多重大更改,以使Metro变得更好,但坏消息是,我们需要解决一些紧迫的问题,以解决不相关的问题开放源代码。 我们希望在几个月内,这个回购协议将处于一个更好的状态,并且会更容易做出贡献。 请给我们一些时间。
对于RN,我通过剥离语言环境的第一部分(可能是当它无法加载“ xx-XX”语言环境时,在屏幕后面发生的瞬间)使它在释放模式下工作。 在以下代码段中, locale
是设备的语言环境,格式为“ xx-XX”。
moment.locale(locale.indexOf("-") === -1 ? locale : locale.substr(0, locale.indexOf('-')))
这是奇怪的行为。
https://stackoverflow.com/a/47260841/175825,您需要为生态系统导入特定的语言环境才能使用它们。
由于这种魔力,我无法使用BigCalendar.momentLocalizer()
来使react-big-calendar显示mm/yy
类的日期,因为它期望加载任何语言环境。
我可以用react-big-calendar打开一个问题,但是遇到的下一个期望特定语言环境的库又如何呢? 还有下一个?
只需添加en-us
语言环境,并默认设置为magic。
只需添加en-us语言环境,然后默认为magic。
它不会解决问题,有些语言(例如西班牙文( es-ES
=> es
))会自动回退。
对于仍在寻找解决方案的任何人,这可能有助于缓解该问题(少数情况除外),但不会解决RN导致在尝试捕获require
期间崩溃的根本问题:
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
* <strong i="7">@param</strong> {string} locale locale to be checked
* <strong i="8">@return</strong> {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';
};
我也使用React Native遇到了这个问题,并且能够通过在Moment中包含所有语言环境来避免此问题,即
import moment from 'moment'
import 'moment/min/locales'
(或者,也提供了moment/min/moment-with-locales
,但它与我们的某些其他格式化程序不兼容。)
这是一个超级烦人的问题。
您是否甚至不必考虑整个语言环境,并且肯定不会仅仅因为您在美国而将“ en-US”硬编码到代码中吗? 我不明白为什么在请求“ en-US”语言环境时不能仅仅接受它。 使人们头疼不已。
一年前我解决了这个问题,但完全忘记了如何解决,然后我必须重新开始。 (我在Angular中使用了一个日期选择器,只是将最小实现放到了这个错误中)。
我在Angular中尝试使用datetime选择器。 如果我将LOCALE设置为en-GB之类的东西,它可以正常工作,但是没有指定任何内容,我得到了这个。 我希望我能找出解决此问题的正确方法
对于RN,我通过剥离语言环境的第一部分(可能是当它无法加载“ xx-XX”语言环境时,在屏幕后面发生的瞬间)使它在释放模式下工作。 在下面的片段中,
locale
是设备的语言环境,格式为“ xx-XX”。
moment.locale(locale.indexOf("-") === -1 ? locale : locale.substr(0, locale.indexOf('-')))
此解决方案适用于我,使用i18n
和momentjs
像这样:
// imports:
import moment from 'moment';
import i18n from './i18n';
import 'moment/locale/fr';
// constructor:
moment.locale(i18n.locale.indexOf('-') === -1 ? i18n.locale : i18n.locale.substr(0, i18n.locale.indexOf('-')));
我仍在尝试运行版本“ moment”的问题:“ ^ 2.22.2”,
最新版本有任何更正吗?
在这个问题上,我会介绍一下。
在构建了可以完美运行的不错的开发之后,我在生产本机中也遇到了这个错误。
使用提出的@adesmet解决方案和以下重构解决了该问题:
function parseLocaleForMoment (language) {
if (language.indexOf('-') === -1) return language
else return language.substr(0, language.indexOf('-'))
}
看起来RN很费劲,以至于编写本机格式化程序都比较容易。 大概只有一行代码,项目符号证明就可以工作。
最终像这样修复它:
const subLocales = [
'ar-tn',
'ar-dz',
'ar-kw',
'ar-ma',
'ar-sa',
'ar-ly',
'de-at',
'de-ch',
'en-sg',
'en-au',
'en-ca',
'en-gb',
'en-ie',
'en-nz',
'es-us',
'es-do',
'fr-ca',
'fr-ch',
'gom-latn',
'hy-am',
'pa-in',
'pt-br',
'sr-cyrl',
'tl-ph',
'tlh',
'tet',
'ms-my',
'it-ch',
'tzl',
'tzm',
'tzm-latn',
'nl-be',
'ug-cn',
'uz-latn',
'zh-cn',
'zh-hk',
'zh-tw'
];
let momentLocale = i18n.locale.toLowerCase();
if (!subLocales.includes(momentLocale)) {
momentLocale = momentLocale.substring(0, 2);
}
moment.locale(momentLocale);
与react native @tapz不幸的是,这似乎可以在Android上运行,但在iOS上却很遗憾:/由于某些原因,我在zh
语言环境中遇到了一些麻烦
这可能是因为zh和其他一些区域设置的格式不同,以区分简体和繁体。 参见https://gist.github.com/jacobbubu/1836273
@ rajivshah3确实我有zh_Hant_HK
不能与tapz方法一起使用我现在正在使用您的方法,这似乎是尽可能平滑地处理此问题的最佳方法,谢谢您的帖子👍
同样的问题,仅在RN生产模式下。
这对我来说似乎很好。
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;
};
只要数据是导入的(或en
)并且尊重大小写,对我们来说似乎就可以正常工作
这真是荒谬。 剥离语言代码的-region
部分不是解决方案。
1)您失去了语言环境的区域性。
2)更糟糕的是,该方法将导致进一步的崩溃。 例如,中文( zh
)在MomentJS语言环境中甚至不存在。 仅定义了zh-cn
, zh-hk
和zh-tw
。 因此,如果您使用上述代码从区域设置字符串中去除区域,则您的应用将立即在大多数中文设备上崩溃。 仅有约8亿智能手机用户。
我对React Native的临时(完全是batshit)解决方法是这样的:
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 <strong i="14">@adesmet</strong>
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嗨,我们有关于RN的瞬间语言环境修复的任何新闻吗?
这只是在使用en-gb
的发布版本上崩溃了。
我遇到了类似的问题。 @simeyla 。
当我将Luxon和timepicker一起添加时,问题弹出了,它们似乎与“ en-US”语言环境有关。
@steveccable好吧,它确实会尝试加载它,以防万一您有更具体的本地化。 当它失败时,它尝试“ en”并成功。 我认为断开连接只是因为某种原因而无法加载“ en-US”对您来说很困难。 这里什么都不会炸毁。 _它应该会正常失败_,然后移至下一个选项。 因此,您必须向我详细介绍您的环境:特别是哪里出了问题?
处理带有例外的“ en-US”或其他有效语言环境的另一个问题是,当您调试并要求调试器阻止异常时,您会反复陷入该异常。
应该有更好,更简单的方法,尤其是对于“ en-US”这样的大型语言环境。
最终,出于速度考虑,应该在前面检查并处理可能有大量观众/使用习惯的这些区域。
我修改了@slorber的解决方案,
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"
同样的问题,仅在RN生产IOS模式下。
这对我来说似乎很好。
从“瞬间”导入瞬间;
导入“时刻/语言环境/ es”;
花了一些时间调试它,谢谢@jorodriguez
这仍然是一个问题
嗨,大家好,
我为您创建了一个小包-> https://github.com/tonix-tuft/moment-utl
npm install --save moment moment-utl
您可以使用以下命令确定所有受支持的瞬间语言环境,而无需提前加载它们:
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 };
moment-utl
对等项取决于moment
,但它捆绑了所有moment
语言环境
在构建moment
开发依赖包的过程中从moment/locale
目录中获取它们。
但是,由于moment
是对等依赖项,因此如果使用ES6并要确保allSupportedLocales
和allSupportedLocalesMap
都使用moment
的最新语言环境您已在项目中安装的moment-utl
(例如,如果moment
某天添加了一个新的语言环境,那么应该可以使您满意),然后您还可以使用moment-utl-locales
moment-utl
提供的moment-utl-locales
脚本。
您可以将其与npx
命令一起使用:
npm install -g npx # Install npx if you don't have it yet
npx moment-utl-locales # Run this command from your project's root folder
使用此脚本时,只需确保先运行它,然后再将代码与Rollup或Webpack捆绑在一起(无论使用哪种方式),因此在捆绑程序遇到它们并将它们添加到它们之前,它将生成最新的语言环境数组和对象。您的最终捆绑包。
我希望这有帮助!
要回复@adammcarth ,请在此处检查我的答案: https :
这个问题困扰了Odoo的家伙,建议的解决方法是手动创建en-us文件。 叹。
我不明白的是,为什么如以上某些注释所述,如果加载程序应该知道它已经具有“ en”并且没有动态导入它,为什么现在尝试加载en-us文件。
无论如何,对于RN用户而言,这仍然是一场噩梦。 最糟糕的是,该问题仅发生在生产版本中。
隐藏的默认值会带来很多惊喜...
这个问题困扰了Odoo的家伙,建议的解决方法是手动创建en-us文件。 叹。
我不明白的是,为什么如以上某些注释所述,如果加载程序应该知道它已经具有“ en”并且没有动态导入它,为什么现在尝试加载en-us文件。
无论如何,对于RN用户而言,这仍然是一场噩梦。 最糟糕的是,该问题仅发生在生产版本中。
隐藏的默认值会带来很多惊喜...
我为此得到👎,但我的解决方案是将moment
换成dayjs
。 因为他们共享相同的功能/ API命名,所以对我来说就像find all + replace all
一样简单。
只是分享我对可能想考虑这一点的人所做的事情。
最有用的评论
@icambron我的环境是一个使用npm来控制我的依赖关系的React Native应用程序,即使在最小的示例应用程序中,我也能够复制故障。 问题在于,在loadLocale函数中,它尝试在名称为en-US的require('./ locale /'+ name)的情况下失败。 如果该要求在发行版本中失败,则将导致应用程序崩溃,并带有如下所示的堆栈跟踪:
查看代码,因为getLocale看到我的键(“ en-US”)不是数组,所以它不尝试匹配“ en”就落入loadLocale,只有在进入chooseLocale函数时才会发生。
编辑:在更仔细地查看了selectLocale函数之后,它仍然会首先尝试选择'en-US',然后在尝试'en'之前失败需求,因此失败的需求甚至导致崩溃的应用程序仍然会发生如果这是一个数组。
同样令人奇怪的是,它断开的位置位于try / catch内,但仍然会导致崩溃。 这实际上是这里真正令人困惑的事情。
编辑2:请注意,在进行调试(__DEV__)生成时,require会优雅地失败,然后确实会下降为使用'en'。 我不确定为什么__PROD__中的require如此具有爆炸性,但是肯定会在此中断。
编辑3:从require js文档中,“如果不表达依赖关系,由于RequireJS异步加载脚本并且速度混乱,您可能会获得加载错误。” 因此,try / catch不太可能真正将我们保存在这里,因为try / catch只能真正帮助解决同步错误。