Module Federation项目中实现i18n拆分与优化 - 第一篇
接着上一篇文章,本以为已经完美的完成了分离。项目测试的过程中,发现加载MF组件之后,宿主应用的翻译就全乱掉了。本篇博客将分享这一经历,并通过阅读源码来定位和解决问题。
问题描述
在我们的项目中,宿主应用和MF(Module Federation)组件各自使用了自己的i18n配置,并且都调用了 i18n.use(initReactNext)
。不幸的是,这导致了一个严重的问题:后初始化的i18n配置覆盖了前者,从而引发宿主应用的翻译文案全部消失的问题。
// 宿主应用的i18n初始化
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
resources: {
en: {
translation: {
welcome: "Welcome to our app"
}
}
},
lng: "en",
fallbackLng: "en"
});
// MF组件的i18n初始化
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.createInstance().use(initReactI18next).init({
resources: {
en: {
translation: {
hello: "Hello from MF component"
}
}
},
lng: "en",
fallbackLng: "en"
});
上面是示例代码
问题分析
经过研究,我们发现问题的根源在于i18n的 use
方法。 i18n.use(initReactI18next)
其实是向i18n实例中注入了一个插件,这样在多个实例之间会发生配置覆盖。
我们来简单的看一看源码,来理解这个问题。
//initReactI18next.js
import { setDefaults } from './defaults.js';
import { setI18n } from './i18nInstance.js';
export const initReactI18next = {
type: '3rdParty',
init(instance) {
setDefaults(instance.options.react);
setI18n(instance);
},
};
// useTranslation.js
export const useTranslation = (ns, props = {}) => {
// assert we have the needed i18nInstance
const { i18n: i18nFromProps } = props;
const { i18n: i18nFromContext, defaultNS: defaultNSFromContext } = useContext(I18nContext) || {};
const i18n = i18nFromProps || i18nFromContext || getI18n();
//...
}
上面是initReactI18next和useTranslation的两段源码。不难发现,useTranslation会通过getI18n()来获取i18n对象的。然而initReactI18next的init方法里面调用了setI18n(instance)。所以后一个总是会覆盖前一个。放到具体的例子中来说,因为MF组件是在宿主之后运行的,所以他会将宿主应用的i18n对象覆盖掉,导致宿主应用翻译发生错误。
解决方案
为了避免覆盖问题,我们决定采用一种分离策略:MF组件不再运行 i18n.use(initReactI18next)
,而是通过 I18nNextProvider
来传入自己的i18n对象。这可以有效避免配置被覆盖,并确保每个模块都有独立的i18n实例。
使用 I18nNextProvider
最后,在MF组件中使用 I18nNextProvider
将i18n实例传递给React:
import React from 'react';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';
const MyComponent = () => {
return (
<I18nextProvider i18n={i18n}>
// 你的组件代码
</I18nextProvider>
);
};
export default MyComponent;
通过这种方式,宿主应用与MF组件各自拥有独立的i18n实例,从而避免了配置覆盖的问题。
总结
在Module Federation项目中实现i18n的分离可以通过避免多次调用 i18n.use(initReactI18next)
来实现。具体的解决方案是让MF组件不再调用该方法,而是通过 I18nextProvider
传入独立的i18n对象。这样不仅能有效避免配置覆盖,还能确保每个模块都能正确处理自己的翻译逻辑。希望这篇博客能为你在微前端架构中的i18n实现提供一些帮助。