# node: 区域设置检测与中间件 URL: https://generaltranslation.com/zh/docs/node/guides/middleware.mdx --- title: 区域设置检测与中间件 description: 如何检测用户的区域设置,并使用 withGT 为每个请求设置它 --- `gt-node` 中的每个翻译函数都需要知道当前请求面向的是哪个区域设置。[`withGT`](/docs/node/api/with-gt) 会使用异步本地存储来设置这一上下文——只需包装你的请求处理函数,后续所有翻译调用都会自动使用正确的区域设置。 ## `withGT` 的工作原理 `withGT` 接收一个区域设置字符串和一个回调函数。在该回调函数内部,[`getGT()`](/docs/node/api/get-gt)、[`getMessages()`](/docs/node/api/get-messages) 和 [`getLocale()`](/docs/node/api/get-locale) 都会读取你设置的区域设置: ```js import { withGT, getLocale } from 'gt-node'; app.use((req, res, next) => { const locale = detectLocale(req); withGT(locale, () => next()); }); ``` 在 `withGT` 上下文之外调用翻译函数时,将使用 `defaultLocale`。务必使用 `withGT` 包装请求处理逻辑。 ## 区域设置检测策略 ### `Accept-Language` 请求头 使用 [`getRequestLocale`](/docs/node/api/get-request-locale) 解析 `Accept-Language` 请求头,并将其与你配置的区域设置相匹配: ```js import { getRequestLocale } from 'gt-node'; function detectLocale(req) { return getRequestLocale(req); } ``` `getRequestLocale` 会自动处理质量值、通配符项以及语言和区域匹配。 ### 基于 cookie 在不同会话之间保留用户的语言选择: ```js import cookieParser from 'cookie-parser'; app.use(cookieParser()); function detectLocale(req) { return req.cookies.locale || 'en'; } // 设置语言偏好的接口 app.post('/api/set-language', (req, res) => { res.cookie('locale', req.body.locale, { maxAge: 365 * 24 * 60 * 60 * 1000 }); res.json({ ok: true }); }); ``` ### URL 参数 从 URL 路径中提取区域设置 (例如 `/es/api/greeting`) : ```js function detectLocale(req) { const segments = req.path.split('/').filter(Boolean); const supported = new Set(['es', 'fr', 'ja', 'de']); if (segments[0] && supported.has(segments[0])) { return segments[0]; } return 'en'; } ``` ### 查询参数 使用 `?lang=` 查询参数: ```js function detectLocale(req) { return req.query.lang || 'en'; } ``` ## 串联策略 在实际使用中,通常需要按优先级顺序依次尝试多种策略: ```js function detectLocale(req) { // 1. 显式查询参数(最高优先级) if (req.query.lang) return req.query.lang; // 2. Cookie(用户保存的偏好设置) if (req.cookies?.locale) return req.cookies.locale; // 3. Accept-Language 请求头(浏览器默认值) const acceptLang = req.headers['accept-language']?.split(',')[0]; if (acceptLang) return acceptLang; // 4. 默认值 return 'en'; } ``` ## Express 中间件 完整的 Express 中间件 setup: ```js title="middleware/locale.js" import { withGT } from 'gt-node'; export function localeMiddleware(req, res, next) { const locale = req.query.lang || req.cookies?.locale || req.headers['accept-language']?.split(',')[0] || 'en'; withGT(locale, () => next()); } ``` ```js title="server.js" import express from 'express'; import cookieParser from 'cookie-parser'; import { initializeGT } from 'gt-node'; import { localeMiddleware } from './middleware/locale.js'; initializeGT({ defaultLocale: 'en', locales: ['en', 'es', 'fr', 'ja'], projectId: process.env.GT_PROJECT_ID, }); const app = express(); app.use(cookieParser()); app.use(localeMiddleware); ``` ## Fastify 中间件 同样的 pattern 也适用于 Fastify,可使用 `preHandler` Hook: ```js title="server.js" import Fastify from 'fastify'; import cookie from '@fastify/cookie'; import { initializeGT, withGT, getGT } from 'gt-node'; initializeGT({ defaultLocale: 'en', locales: ['en', 'es', 'fr', 'ja'], projectId: process.env.GT_PROJECT_ID, }); const app = Fastify(); await app.register(cookie); app.addHook('preHandler', (req, reply, done) => { const locale = req.query.lang || req.cookies?.locale || req.headers['accept-language']?.split(',')[0] || 'en'; withGT(locale, () => done()); }); app.get('/api/greeting', async (req, reply) => { const gt = await getGT(); return { message: gt('Hello, world!') }; }); app.listen({ port: 3000 }); ``` ## 读取当前区域设置 在 `withGT` 上下文中的任意位置使用 [`getLocale()`](/docs/node/api/get-locale),即可获取最终确定的区域设置: ```js import { getLocale } from 'gt-node'; app.get('/api/info', async (req, res) => { const locale = getLocale(); res.json({ currentLocale: locale }); }); ``` ## 后续步骤 * [`withGT` API 参考](/docs/node/api/with-gt) * [`getLocale` API 参考](/docs/node/api/get-locale) * [`getRequestLocale` API 参考](/docs/node/api/get-request-locale) * [字符串翻译模式](/docs/node/guides/strings) — 了解如何翻译内容 * [本地翻译存储](/docs/node/guides/local-tx) — 将译文随应用一起打包