You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native中为JavaScript Intl API实现Polyfill?

已关闭: 此问题源于我方bug,详情见答案。


问题描述

我正在安卓平台测试一款自定义JavaScript运行时,使用的示例React Native应用为Zulip Mobile(对应某GitHub提交版本)。该运行时支持多数现代JavaScript特性,但缺少对Intl API的支持。

这款RN应用通过react-intl的IntlProvider组件使用Intl,核心代码如下:

import { IntlProvider, IntlContext } from 'react-intl';

// ...

export default function TranslationProvider(props: Props): Node {
  const { children } = props;
  const language = useGlobalSelector(state => getGlobalSettings(state).language);

  return (
    <IntlProvider locale={language} textComponent={Text} messages={messages[language]}>
      <TranslationContextTranslator>{children}</TranslationContextTranslator>
    </IntlProvider>
  );
}

运行时触发以下错误:

ReferenceError: 'Intl' is not defined

Component Stack:

    in IntlProvider
    in Unknown
    in RCTView
    in Unknown
    in L
    in Connect(L)
    in Unknown
    in RNCSafeAreaProvider
    in Unknown
    in Unknown
    in n
    in Unknown
    in b
    in O
    in Unknown
    in RCTView
    in Unknown
    in RCTView
    in Unknown
    in b

Call Stack:

    at <anonymous> (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at o (index.android.bundle)
    at jt (index.android.bundle)
    at ul (index.android.bundle)
    at ql (index.android.bundle)
    at Fa (index.android.bundle)
    at Ua (index.android.bundle)
    at La (index.android.bundle)
    at Ea (index.android.bundle)
    at ft (index.android.bundle)
    at Te (index.android.bundle)
    at Pe (index.android.bundle)
    at notify (index.android.bundle)
    at notifyNestedSubs (index.android.bundle)
    at f (index.android.bundle)
    at b (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at call (native)
    at v (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at call (native)
    at v (index.android.bundle)
    at o (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at u (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at apply (native)
    at <anonymous> (index.android.bundle)
    at k (index.android.bundle)
    at w (index.android.bundle)
    at callReactNativeMicrotasks (index.android.bundle)
    at value (index.android.bundle)
    at <anonymous> (index.android.bundle)
    at value (index.android.bundle)
    at value (index.android.bundle)
    at value (index.android.bundle)

我尝试用intl和formatjs包做Polyfill,但均未成功,错误信息一致。我没有React Native开发经验,可能Polyfill方法有误,希望得到指点。

已尝试的两种Polyfill写法:

写法一

// index.js

/* @flow strict-local */
// React Navigation requires this react-native-gesture-handler import,
// as the very first import of this entry-point file.  See our #5373.
import 'react-native-gesture-handler';
import IntlPolyfill from 'intl'; // <-
import { AppRegistry } from 'react-native';
import ZulipMobile from './src/ZulipMobile';

if (!globalThis.Intl) {
    globalThis.Intl = IntlPolyfill;
}

AppRegistry.registerComponent('ZulipMobile', () => ZulipMobile);

写法二

// index.js

/* @flow strict-local */
// React Navigation requires this react-native-gesture-handler import,
// as the very first import of this entry-point file.  See our #5373.
import 'react-native-gesture-handler';
import { AppRegistry } from 'react-native';
import ZulipMobile from './src/ZulipMobile';

// polyfills
import '@formatjs/intl-getcanonicallocales/polyfill';
import '@formatjs/intl-locale/polyfill';
import '@formatjs/intl-displaynames/polyfill';
import '@formatjs/intl-displaynames/locale-data/en';

if (!global.Intl) {
  throw new Error('Intl is missing???');
}

AppRegistry.registerComponent('ZulipMobile', () => ZulipMobile);

也参考过多个相关问题的解决方案,但均无效。


解决方案

1. 调整Polyfill加载顺序,确保全局注入优先

问题大概率是react-intl在Polyfill注入全局前就已加载。修改index.js,将Polyfill的导入和全局赋值放在所有业务代码之前(除了强制要求的react-native-gesture-handler):

// index.js
import 'react-native-gesture-handler';

// 优先加载Intl Polyfill及对应语言包
import IntlPolyfill from 'intl';
import 'intl/locale-data/jsonp/en'; // 按需添加应用需要的语言包

// 注入全局对象
if (typeof globalThis.Intl === 'undefined') {
  globalThis.Intl = IntlPolyfill;
}

// 再导入其他依赖和应用入口
import { AppRegistry } from 'react-native';
import ZulipMobile from './src/ZulipMobile';

AppRegistry.registerComponent('ZulipMobile', () => ZulipMobile);

2. 直接向IntlProvider传入Polyfill实例

react-intl支持手动传入Intl实例,无需依赖全局变量。修改TranslationProvider组件:

import { IntlProvider, IntlContext } from 'react-intl';
import IntlPolyfill from 'intl';
import 'intl/locale-data/jsonp/en'; // 按需添加语言包

// ...

export default function TranslationProvider(props: Props): Node {
  const { children } = props;
  const language = useGlobalSelector(state => getGlobalSettings(state).language);

  return (
    <IntlProvider 
      locale={language} 
      textComponent={Text} 
      messages={messages[language]}
      intl={new IntlPolyfill.Intl(language)} // 手动传入Polyfill实例
    >
      <TranslationContextTranslator>{children}</TranslationContextTranslator>
    </IntlProvider>
  );
}

3. 确认自定义运行时的全局对象

部分自定义JS运行时可能不使用globalThis或global作为全局对象,可先打印确认:

// 在index.js最顶部添加(在任何导入之前)
console.log('全局对象:', this);
console.log('当前Intl:', this.Intl);

根据打印结果调整Polyfill的赋值目标,比如如果全局对象是window,就赋值给window.Intl。

4. 补全formatjs的所有必要Polyfill

若使用formatjs,需确保安装并导入react-intl依赖的全部Polyfill包:

import 'react-native-gesture-handler';

// 导入所有基础Polyfill
import '@formatjs/intl-polyfill';
import '@formatjs/intl-getcanonicallocales/polyfill';
import '@formatjs/intl-locale/polyfill';
import '@formatjs/intl-displaynames/polyfill';
import '@formatjs/intl-displaynames/locale-data/en';
// 补充react-intl常用的格式化类Polyfill
import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/locale-data/en';
import '@formatjs/intl-numberformat/polyfill';
import '@formatjs/intl-numberformat/locale-data/en';

// 验证Polyfill是否生效
if (!globalThis.Intl) {
  throw new Error('Intl Polyfill加载失败');
}

import { AppRegistry } from 'react-native';
import ZulipMobile from './src/ZulipMobile';

AppRegistry.registerComponent('ZulipMobile', () => ZulipMobile);

内容的提问来源于stack exchange,提问作者Rynco Maekawa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:54:54