Remix v2 中使用 remix-i18n 进行国际化翻译

i18n(国际化)是指将应用程序设计为能够适应多种语言和区域设置,以满足不同国家和地区的不同语言和文化习惯。在现代软件开发中,i18n 已经成为了非常重要的一部分。为了让应用程序更好地支持不同语言和文化习惯,开发者需要使用各种工具和技术进行处理。Remix i18n 是一种基于 Remix 开发框架的 i18n 处理方式,它使得开发者能够非常方便地实现应用程序的国际化需求。本文将介绍 Remix i18n 的原理、使用方法以及适用场景。

META

  • NPM: https://www.npmjs.com/package/remix-i18n
  • 源码: https://github.com/willin/remix-i18n
  • 示例项目: https://github.com/willin/remix-i18n/tree/main/documents

文章目录

  • META
  • 安装
  • 配置说明
  • 示例
    • 初始化
    • 客户端设置
    • 服务器端设置
    • 进行语言切换
    • 使用翻译模板
  • 比较
    • remix-i18next
    • remix-rosetta-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

示例

正常流程,其中步骤可以调整:

  1. 初始化 i18n 插件
  2. 添加语言翻译
  3. 进行客户端和服务器端的配置
  4. 使用模板语言进行页面开发/改造
  5. 手动切换语言菜单组件封装 *

初始化

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 }

比较

remix-i18next

需要同时依赖 react-i18nexti18next 使用起来会麻烦许多,但其支持远程异步加载翻译,适合大型项目。

remix-rosetta-i18n

使用了相同的 rosetta 作为底层支持(或者说精简改进过, remix-i18n 中并未依赖 rosetta)。该项目已经停滞两年未更新。

小结

在国际化的今天,i18n已经不再是一个可有可无的功能,而是一个不可或缺的基础模块。通过使用i18n,我们能够更好地面对多语言、多平台、多文化的挑战,为产品的国际拓展打下坚实的基础。在开发过程中,我们要尽可能地使用i18n标准,遵循i18n最佳实践,以提高产品的兼容性和可扩展性。让i18n成为我们的日常开发习惯,让我们的应用能够在全球范围内更好地服务用户。

你可能感兴趣的:(前端,javascript,开发语言)