solidstart的i18n解决方案

前端开发

solidstart发布了正式版本1.0,solidjs以性能著称,据说是能替换react的存在,而solidstart则是对应的nextjs

这几年前端框架也可以卷起来了,一众前端框架脱颖而出,另一个值得关注的框架sveltekit,由于最新svelte 5.0的发布据说修复了4.0很多问题,而sveltekit则是对应的是react的nextjs

这两个框架和生态都远不及react/nextjs系列,但是长远来看值得关注。

由于有个新的项目需要,目前正在测试这两个框架为了选择技术栈,由于该项目有多国语言的需要,今天测试了一下solidstart,顺便看了下i18n库,它的文档非常不成熟,用的是@solid-primitives/i18n这个库,这里记录一下实现过程,但是遗憾的是该方案没有生成出带有语言标识的URL,这对SEO很不友好,以后实现了再更新吧。

大概是i18n这个库的文档是为了solid写的,又或者版本不对,它并没有详细的写清楚该怎么用,新手肯定会非常迷茫。

文档目录结构

每个语言目录下的ts文件

import global from './global.json';
import home from './home.json';
export const dict = {
  global,
  home,
};

入口文件:

App.tsx

import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
//import { Suspense } from "solid-js";
import Nav from "~/components/Nav";
import "./app.css";
import * as i18n from "@solid-primitives/i18n";
import {
  Suspense,
  createResource,
  createSignal,
  Show
} from 'solid-js';

import type * as en from "./locales/en/en";

export type Locale = "en" | "zh-cn";
export type RawDictionary = typeof en.dict;
export type Dictionary = i18n.Flatten<RawDictionary>;

async function fetchDictionary(locale: Locale): Promise<Dictionary> {
  const dict: RawDictionary = (await import(`./locales/${locale}/${locale}.ts`)).dict;
  return i18n.flatten(dict); // flatten the dictionary to make all nested keys available top-level
}

function extractLocale(path: string, defaultLocale = "en") {
  const segments = path.split("/");
  let locale = segments[1];

  if (locale && locale.length === 2) {
    return locale;
  } else {
    return defaultLocale;
  }
}

export default function App() {

  const [locale, setLocale] = createSignal<Locale>("en");

  const [dict] = createResource(locale, fetchDictionary);

  dict(); // => Dictionary | undefined
  // (undefined when the dictionary is not loaded yet)

  const t = i18n.translator(dict);


  return (    
    <Router
      root={props => (
        <>
          <Nav />
          <Suspense>
            <Show when={dict()}>
              {dict => {
                dict(); // => Dictionary (narrowed by Show)

                const t = i18n.translator(dict);

                t("home.hero"); // => string

                return (
                  <div>
                    <p>Current locale: {locale()}</p>
                    <div>
                      <button onClick={() => setLocale("en")}>English</button>
                      <button onClick={() => setLocale("zh-cn")}>简体中文</button>
                    </div>

                    <h4>{t("global.hello", { name: "John" })}</h4>

                  </div>
                );
              }}
            </Show>      
            {props.children}

          </Suspense>
        </>
      )}
    >
      <FileRoutes />
    </Router>
  );
}

在页面或组件中使用

import LanguageSwitcher from "~/components/LanguageSwitcher";
import * as i18n from "@solid-primitives/i18n";
import {
  createResource,
  startTransition,
  useContext,
  createSignal,
  Show
} from 'solid-js';

import type * as en from "../locales/en/en";
export type Locale = "en" | "zh-cn";
export type RawDictionary = typeof en.dict;
export type Dictionary = i18n.Flatten<RawDictionary>;

async function fetchDictionary(locale: Locale): Promise<Dictionary> {
  const dict: RawDictionary = (await import(`../locales/${locale}/${locale}.ts`)).dict;
  return i18n.flatten(dict); // flatten the dictionary to make all nested keys available top-level
}

最后

export default function Home() {

  const [locale, setLocale] = createSignal<Locale>("en");
  const [commonDict] = createResource(locale, fetchDictionary);
  const t = i18n.translator(commonDict);

  return (
    <main class="text-center mx-auto text-gray-700 p-4">
      <p class="my-4">
        <span>Home</span>
        {t("home.hero")}
      </p>
    </main>
  );
}

整体下来挺复杂的说实话。

Post Comment