i18n(国际化)是指将应用程序设计为能够适应多种语言和区域设置,以满足不同国家和地区的不同语言和文化习惯。在现代软件开发中,i18n 已经成为了非常重要的一部分。为了让应用程序更好地支持不同语言和文化习惯,开发者需要使用各种工具和技术进行处理。Remix i18n 是一种基于 Remix 开发框架的 i18n 处理方式,它使得开发者能够非常方便地实现应用程序的国际化需求。本文将介绍 Remix i18n 的原理、使用方法以及适用场景。
npm install --save remix-i18n
如果使用 yarn
或者 pnpm
:
yarn add remix-i18n
# 或
pnpm i remix-i18n
export interface RemixI18nOptions {
/**
* Define the list of supported languages, this is used to determine if one of
* the languages requested by the user is supported by the application.
* This should be be same as the supportedLngs in the i18next options.
*/
supportedLanguages: string[];
/**
* Define the fallback language that it's going to be used in the case user
* expected language is not supported.
* This should be be same as the fallbackLng in the i18next options.
*/
fallbackLng: string;
}
export declare class RemixI18n {
private currentLocale;
fallbackLng: string;
supportedLanguages: string[];
private dict;
constructor(options: RemixI18nOptions);
locale: (lang?: string | undefined) => string;
set: (lang: string, dict: I18nDict) => void;
t: (key: string, params?: any, lang?: string | undefined) => string;
private onChangeLanguage?;
setOnChange: (fn: (locale: string) => void) => void;
}
即创建时,需要两个参数:
supportedLanguages
: 支持的语言数组,示例: ['zh','en']
fallbackLng
: 默认语言,示例: zh
正常流程,其中步骤可以调整:
import { RemixI18n } from 'remix-i18n';
const i18n = new RemixI18n({
supportedLanguages: ['en', 'tl', 'da', 'zh'],
fallbackLng: 'zh'
});
然后添加语言翻译:
i18n.set('locale', {
hello: '你好'
});
修改 entry.client.tsx
:
import { RemixBrowser } from '@remix-run/react';
import { startTransition, StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';
import { I18nProvider } from 'remix-i18n';
import { i18n, getLocale } from './i18n';
const locale = getLocale(window.location.pathname);
i18n.locale(locale);
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<I18nProvider i18n={i18n}>
<RemixBrowser />
</I18nProvider>
</StrictMode>
);
});
其中 getLocale
可以这样实现:
export function getLocale(pathname: string): string {
const [, locale = ''] = pathname.split('/');
if (i18n.supportedLanguages.includes(locale)) {
return locale;
}
return i18n.fallbackLng;
}
修改 entry.server.ts
:
import isbot from 'isbot';
import { renderToReadableStream } from 'react-dom/server';
import { RemixServer } from '@remix-run/react';
import { I18nProvider } from 'remix-i18n';
import { i18n, getLocale } from './i18n';
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
loadContext: AppLoadContext
) {
const locale = getLocale(new URL(request.url).pathname);
i18n.locale(locale);
const body = await renderToReadableStream(
<I18nProvider i18n={i18n}>
<RemixServer context={remixContext} url={request.url} />
</I18nProvider>,
{
signal: request.signal,
onError(error: unknown) {
// Log streaming rendering errors from inside the shell
console.error(error);
responseStatusCode = 500;
}
}
);
if (isbot(request.headers.get('user-agent'))) {
await body.allReady;
}
responseHeaders.set('Content-Type', 'text/html');
return new Response(body, {
headers: responseHeaders,
status: responseStatusCode
});
}
可以封装一个切换组件进行前端的切换,这里有一个切换的示例:
const i18n = useI18n();
const location = useLocation();
useEffect(() => {
// 替换语言即可
const locale = getLocale(location.pathname);
if (locale !== i18n.locale()) {
// 核心切换语言的方法:
i18n.locale(locale);
}
}, [location]);
const { t } = useI18n();
// jsx
<h1>{t('hello')}</h1>;
复数的使用,示例代码:
// 假设 en 预置为:
{
en: {
warning: 'WARNING: {{ birds }}'',
birds: {
zero: 'birds',
one: 'bird',
two: 'two birds',
few: 'some birds',
many: 'flock of birds'
}
}
};
// 使用:
t('warning', { birds: 2 }
需要同时依赖 react-i18next
和 i18next
使用起来会麻烦许多,但其支持远程异步加载翻译,适合大型项目。
使用了相同的 rosetta 作为底层支持(或者说精简改进过, remix-i18n
中并未依赖 rosetta
)。该项目已经停滞两年未更新。
在国际化的今天,i18n已经不再是一个可有可无的功能,而是一个不可或缺的基础模块。通过使用i18n,我们能够更好地面对多语言、多平台、多文化的挑战,为产品的国际拓展打下坚实的基础。在开发过程中,我们要尽可能地使用i18n标准,遵循i18n最佳实践,以提高产品的兼容性和可扩展性。让i18n成为我们的日常开发习惯,让我们的应用能够在全球范围内更好地服务用户。