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>
);
}整体下来挺复杂的说实话。