文章目录[隐藏]
实操指南:实现多语言店铺切换的6个可靠方案
引言:为什么多语言店铺对跨境电商至关重要
在全球化的电商时代,语言壁垒是阻碍跨境交易的最大障碍之一。据统计,超过70%的消费者更倾向于使用母语浏览和购买商品,而超过50%的消费者表示,如果网站没有他们的母语版本,他们不会进行购买。对于基于WordPress的电商店铺来说,实现多语言功能不仅能提升用户体验,还能显著提高转化率和国际市场份额。
WordPress作为全球最流行的内容管理系统,拥有丰富的多语言解决方案生态系统。本文将深入探讨6种可靠的WordPress多语言店铺实现方案,从简单的插件应用到高级自定义开发,为行业新人和程序员提供全面的技术指导。
方案一:使用WPML插件实现完整多语言店铺
WPML插件概述与安装配置
WPML(WordPress Multilingual Plugin)是市场上最成熟、功能最全面的WordPress多语言插件之一。它专门为电商网站设计,与WooCommerce完美集成,支持超过40种语言。
安装与基础配置步骤:
- 从WordPress官方插件库或WPML官网下载插件
-
安装并激活WPML核心插件及以下组件:
- WPML Multilingual CMS
- WPML String Translation
- WPML Media Translation
- WooCommerce Multilingual(针对电商)
// 示例:检查WPML是否激活并获取当前语言
function check_wpml_status() {
if (function_exists('icl_object_id')) {
$current_lang = apply_filters('wpml_current_language', NULL);
$default_lang = apply_filters('wpml_default_language', NULL);
return array(
'current' => $current_lang,
'default' => $default_lang
);
}
return false;
}
// 在主题中调用语言切换器
function display_wpml_language_switcher() {
if (function_exists('icl_get_languages')) {
$languages = icl_get_languages('skip_missing=0&orderby=code');
if (!empty($languages)) {
echo '<div class="language-switcher">';
foreach ($languages as $language) {
$class = $language['active'] ? 'active' : '';
echo '<a class="' . $class . '" href="' . $language['url'] . '">';
echo '<img src="' . $language['country_flag_url'] . '" alt="' . $language['language_code'] . '" />';
echo $language['native_name'];
echo '</a>';
}
echo '</div>';
}
}
}
WooCommerce与WPML的深度集成
WPML为WooCommerce提供了专门的模块,确保产品、分类、属性和购物车都能完美支持多语言。
关键配置要点:
- 产品同步设置:确保产品在不同语言间保持库存、价格和SKU同步
- 货币切换功能:结合WPML和货币插件实现语言与货币的关联切换
- 翻译管理:使用专业翻译服务或编辑器手动翻译产品内容
// 示例:获取多语言产品ID
function get_multilingual_product_id($product_id, $language_code = null) {
if (function_exists('icl_object_id')) {
$type = get_post_type($product_id);
$multilingual_id = apply_filters(
'wpml_object_id',
$product_id,
$type,
true,
$language_code
);
return $multilingual_id;
}
return $product_id;
}
// 在WooCommerce模板中使用
$current_language = apply_filters('wpml_current_language', NULL);
$product_id = get_the_ID();
$translated_product_id = get_multilingual_product_id($product_id, $current_language);
优势与局限性分析
优势:
- 完整的电商多语言解决方案
- 强大的翻译管理界面
- 良好的SEO支持(hreflang标签自动生成)
- 与主流主题和插件兼容性好
局限性:
- 商业插件,需要付费授权
- 对服务器资源要求较高
- 学习曲线相对陡峭
方案二:Polylang插件 + WooCommerce多语言方案
Polylang免费方案实施
Polylang是另一款流行的WordPress多语言插件,提供免费版本和付费的Polylang Pro版本。与WPML不同,Polylang使用更直观的语言管理方式,将每种语言的内容作为独立文章/页面处理。
基础设置步骤:
- 安装Polylang插件
- 添加需要的语言
- 配置语言检测方式(URL前缀、子域名或域名)
- 安装Polylang for WooCommerce扩展
// 示例:创建自定义语言切换器
function custom_polylang_switcher() {
if (function_exists('pll_the_languages')) {
$languages = pll_the_languages(array('raw' => 1));
if (!empty($languages)) {
echo '<ul class="polylang-switcher">';
foreach ($languages as $language) {
$active_class = $language['current_lang'] ? 'active' : '';
echo '<li class="' . $active_class . '">';
echo '<a href="' . $language['url'] . '" hreflang="' . $language['slug'] . '">';
echo '<span class="flag">' . $language['flag'] . '</span>';
echo '<span class="name">' . $language['name'] . '</span>';
echo '</a>';
echo '</li>';
}
echo '</ul>';
}
}
}
// 在header.php中调用
add_action('wp_header', 'custom_polylang_switcher');
高级自定义功能开发
对于需要更多控制权的开发者,Polylang提供了丰富的API和钩子:
// 示例:根据语言加载不同的样式表
function load_language_specific_styles() {
if (function_exists('pll_current_language')) {
$current_lang = pll_current_language();
switch ($current_lang) {
case 'ar':
wp_enqueue_style('rtl-style', get_template_directory_uri() . '/css/rtl.css');
break;
case 'ja':
wp_enqueue_style('japanese-font', 'https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap');
break;
}
}
}
add_action('wp_enqueue_scripts', 'load_language_specific_styles');
// 示例:语言特定的SEO标题
function language_specific_seo_title($title) {
if (function_exists('pll_current_language') && is_product()) {
$current_lang = pll_current_language();
$product_id = get_the_ID();
if ($current_lang !== pll_default_language()) {
$title .= ' | ' . strtoupper($current_lang) . ' Version';
}
}
return $title;
}
add_filter('wpseo_title', 'language_specific_seo_title');
与WooCommerce的集成技巧
Polylang for WooCommerce扩展提供了基础的产品多语言支持,但某些高级功能需要自定义开发:
// 示例:同步产品库存 across languages
function sync_product_stock_across_languages($product_id, $stock_quantity, $product) {
if (!function_exists('pll_get_post_translations')) {
return;
}
// 获取所有语言版本的产品ID
$translations = pll_get_post_translations($product_id);
foreach ($translations as $lang => $translated_id) {
// 跳过当前产品
if ($translated_id == $product_id) {
continue;
}
// 更新其他语言版本的库存
$translated_product = wc_get_product($translated_id);
if ($translated_product) {
$translated_product->set_stock_quantity($stock_quantity);
$translated_product->save();
}
}
}
add_action('woocommerce_product_set_stock', 'sync_product_stock_across_languages', 10, 3);
方案三:Weglot翻译服务集成方案
Weglot云端翻译服务介绍
Weglot采用不同的多语言实现思路:它通过JavaScript和API在网站前端实时翻译内容,同时提供可视化编辑界面。这种方法特别适合非技术用户和需要快速上线的项目。
集成步骤:
- 注册Weglot账户并创建项目
- 安装Weglot WordPress插件
- 配置API密钥和语言设置
- 自定义翻译规则和排除元素
// 示例:手动集成Weglot(不通过插件)
function add_weglot_script_manually() {
// 仅在前端显示
if (is_admin()) {
return;
}
$weglot_api_key = get_option('weglot_api_key');
$original_language = get_option('weglot_original_language', 'en');
$destination_languages = get_option('weglot_destination_languages', ['fr', 'es']);
if (!empty($weglot_api_key) && !empty($destination_languages)) {
?>
<script type="text/javascript" src="https://cdn.weglot.com/weglot.min.js"></script>
<script>
Weglot.initialize({
api_key: '<?php echo esc_js($weglot_api_key); ?>',
originalLanguage: '<?php echo esc_js($original_language); ?>',
destinationLanguages: <?php echo json_encode($destination_languages); ?>,
excludeBlocks: ['.do-not-translate', '.price', '.sku'],
dynamic: [
{
url: '/shop/',
selector: '.product-description'
}
]
});
</script>
<?php
}
}
add_action('wp_footer', 'add_weglot_script_manually');
自定义翻译规则与排除项
对于电商网站,某些元素不应被翻译,如产品SKU、特定技术术语等:
// 示例:通过PHP动态排除翻译元素
function customize_weglot_exclusions() {
if (function_exists('weglot_get_current_language') && weglot_get_current_language() !== weglot_get_original_language()) {
// 添加特定CSS类到不应翻译的元素
add_filter('body_class', function($classes) {
$classes[] = 'weglot-translated';
return $classes;
});
// 动态排除价格元素
add_filter('woocommerce_get_price_html', function($price_html) {
return '<span class="weglot-exclude">' . $price_html . '</span>';
}, 10, 1);
}
}
add_action('template_redirect', 'customize_weglot_exclusions');
性能优化与缓存策略
由于Weglot依赖JavaScript翻译,性能优化尤为重要:
// 示例:优化Weglot加载性能
function optimize_weglot_performance() {
// 异步加载Weglot脚本
add_filter('script_loader_tag', function($tag, $handle) {
if (strpos($handle, 'weglot') !== false) {
return str_replace(' src', ' async src', $tag);
}
return $tag;
}, 10, 2);
// 添加资源提示
add_action('wp_head', function() {
echo '<link rel="preconnect" href="https://cdn.weglot.com" crossorigin>';
echo '<link rel="dns-prefetch" href="https://cdn.weglot.com">';
});
// 缓存翻译数据
add_action('init', function() {
if (isset($_GET['weglot-cache']) && current_user_can('manage_options')) {
// 生成翻译缓存逻辑
generate_weglot_translation_cache();
}
});
}
function generate_weglot_translation_cache() {
// 实现缓存生成逻辑
$languages = ['fr', 'es', 'de'];
$urls = [
home_url('/shop/'),
home_url('/product-category/clothing/'),
// 添加其他重要页面
];
foreach ($languages as $language) {
foreach ($urls as $url) {
// 模拟访问页面以触发翻译缓存
$translated_url = add_query_arg('wg_language', $language, $url);
wp_remote_get($translated_url, array('timeout' => 5));
}
}
}
方案四:自定义多语言数据库架构
设计多语言数据库表结构
对于需要完全控制的大型电商项目,自定义数据库架构可能是最佳选择。这种方法虽然开发成本较高,但提供了最大的灵活性和性能优化空间。
基础表结构设计:
// 示例:创建多语言自定义表
function create_multilingual_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 语言表
$language_table = $wpdb->prefix . 'custom_languages';
$sql = "CREATE TABLE IF NOT EXISTS $language_table (
id INT(11) NOT NULL AUTO_INCREMENT,
code VARCHAR(10) NOT NULL,
name VARCHAR(50) NOT NULL,
native_name VARCHAR(50) NOT NULL,
direction ENUM('ltr', 'rtl') DEFAULT 'ltr',
flag_url VARCHAR(255),
is_default TINYINT(1) DEFAULT 0,
is_active TINYINT(1) DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY code (code)
) $charset_collate;";
// 翻译表
$translation_table = $wpdb->prefix . 'custom_translations';
$sql .= "CREATE TABLE IF NOT EXISTS $translation_table (
id INT(11) NOT NULL AUTO_INCREMENT,
original_id INT(11) NOT NULL,
original_type VARCHAR(50) NOT NULL COMMENT 'post, term, string',
language_code VARCHAR(10) NOT NULL,
translated_title TEXT,
translated_content LONGTEXT,
translated_excerpt TEXT,
meta_data LONGTEXT COMMENT 'Serialized array of meta fields',
status ENUM('draft', 'published', 'needs_review') DEFAULT 'draft',
translator_id INT(11),
translated_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY original_composite (original_id, original_type),
KEY language_status (language_code, status),
FOREIGN KEY (language_code) REFERENCES $language_table(code) ON DELETE CASCADE
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
register_activation_hook(__FILE__, 'create_multilingual_tables');
创建多语言内容管理类
实现一个自定义类来管理多语言内容:
class Custom_Multilingual_Manager {
private $wpdb;
private $current_language;
private $default_language;
public function __construct() {
global $wpdb;
$this->wpdb = $wpdb;
$this->set_current_language();
$this->default_language = $this->get_default_language();
// 初始化钩子
$this->init_hooks();
}
private function set_current_language() {
// 从Cookie、URL参数或浏览器设置检测语言
if (isset($_GET['lang']) && $this->is_valid_language($_GET['lang'])) {
$this->current_language = sanitize_text_field($_GET['lang']);
setcookie('site_language', $this->current_language, time() + 30 * DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN);
} elseif (isset($_COOKIE['site_language']) && $this->is_valid_language($_COOKIE['site_language'])) {
$this->current_language = $_COOKIE['site_language'];
} else {
$browser_lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
$this->current_language = $this->is_valid_language($browser_lang) ? $browser_lang : $this->get_default_language();
}
}
public function get_translated_post($post_id, $post_type = 'post') {
$table = $this->wpdb->prefix . 'custom_translations';
// 如果是默认语言,返回原始内容
if ($this->current_language === $this->default_language) {
return get_post($post_id);
}
// 查询翻译内容
$translation = $this->wpdb->get_row($this->wpdb->prepare(
"SELECT * FROM $table
WHERE original_id = %d
AND original_type = %s
AND language_code = %s
AND status = 'published'",
$post_id,
$post_type,
$this->current_language
));
if ($translation) {
// 创建虚拟文章对象
$original_post = get_post($post_id);
$translated_post = new stdClass();
$translated_post->ID = $post_id;
$translated_post->post_title = $translation->translated_title ?: $original_post->post_title;
$translated_post->post_content = $translation->translated_content ?: $original_post->post_content;
$translated_post->post_excerpt = $translation->translated_excerpt ?: $original_post->post_excerpt;
$translated_post->post_type = $original_post->post_type;
return $translated_post;
}
return get_post($post_id);
}
public function get_language_switcher() {
$languages = $this->get_active_languages();
get_current_url();
$switcher_html = '<div class="custom-language-switcher">';
$switcher_html .= '<ul>';
foreach ($languages as $language) {
$is_current = ($language['code'] === $this->current_language);
$class = $is_current ? 'current-language' : '';
$url = $this->add_language_to_url($current_url, $language['code']);
$switcher_html .= sprintf(
'<li class="%s"><a href="%s" hreflang="%s">%s</a></li>',
esc_attr($class),
esc_url($url),
esc_attr($language['code']),
esc_html($language['name'])
);
}
$switcher_html .= '</ul></div>';
return $switcher_html;
}
private function init_hooks() {
// 过滤文章内容
add_filter('the_posts', [$this, 'translate_posts_query'], 10, 2);
// 过滤菜单项
add_filter('wp_nav_menu_objects', [$this, 'translate_menu_items'], 10, 2);
// 添加hreflang标签
add_action('wp_head', [$this, 'add_hreflang_tags']);
// 重写规则
add_action('init', [$this, 'add_rewrite_rules']);
add_filter('query_vars', [$this, 'add_query_vars']);
}
public function add_rewrite_rules() {
// 添加语言前缀到URL结构
add_rewrite_rule(
'^([a-z]{2})/(.*)?$',
'index.php?lang=$matches[1]&pagename=$matches[2]',
'top'
);
}
}
### 实现URL重写与SEO优化
// 示例:多语言URL重写系统
class Multilingual_Rewrite_System {
public function __construct() {
add_action('init', [$this, 'init_rewrites']);
add_filter('post_link', [$this, 'translate_post_link'], 10, 2);
add_filter('term_link', [$this, 'translate_term_link'], 10, 3);
add_filter('page_link', [$this, 'translate_page_link'], 10, 2);
}
public function init_rewrites() {
$languages = $this->get_active_language_codes();
foreach ($languages as $lang) {
if ($lang === $this->get_default_language()) {
continue; // 默认语言不需要前缀
}
// 重写产品URL
add_rewrite_rule(
'^' . $lang . '/product/([^/]+)/?$',
'index.php?lang=' . $lang . '&product=$matches[1]',
'top'
);
// 重写产品分类URL
add_rewrite_rule(
'^' . $lang . '/product-category/([^/]+)/?$',
'index.php?lang=' . $lang . '&product_cat=$matches[1]',
'top'
);
// 重写页面URL
add_rewrite_rule(
'^' . $lang . '/([^/]+)/?$',
'index.php?lang=' . $lang . '&pagename=$matches[1]',
'top'
);
}
}
public function translate_post_link($permalink, $post) {
$current_lang = $this->get_current_language();
$default_lang = $this->get_default_language();
if ($current_lang === $default_lang) {
return $permalink;
}
// 获取翻译后的slug
$translated_slug = $this->get_translated_slug($post->ID, 'post', $current_lang);
if ($translated_slug) {
$permalink = str_replace(
$post->post_name,
$translated_slug,
$permalink
);
}
// 添加语言前缀
return $this->add_language_prefix($permalink, $current_lang);
}
private function add_language_prefix($url, $language_code) {
$url_parts = parse_url($url);
$path = $url_parts['path'] ?? '';
// 检查是否已有语言前缀
$pattern = '/^/([a-z]{2})//';
if (preg_match($pattern, $path)) {
$path = preg_replace($pattern, '/' . $language_code . '/', $path);
} else {
$path = '/' . $language_code . $path;
}
$url_parts['path'] = $path;
return $this->build_url($url_parts);
}
public function add_hreflang_tags() {
$languages = $this->get_active_languages();
$current_url = $this->get_current_url();
foreach ($languages as $language) {
$url = $this->add_language_to_url($current_url, $language['code']);
printf(
'<link rel="alternate" hreflang="%s" href="%s" />' . "n",
esc_attr($language['code']),
esc_url($url)
);
}
// 添加x-default
$default_url = $this->add_language_to_url($current_url, $this->get_default_language());
printf(
'<link rel="alternate" hreflang="x-default" href="%s" />' . "n",
esc_url($default_url)
);
}
}
## 方案五:Headless WordPress + 多语言前端架构
### 构建多语言REST API扩展
对于现代Headless WordPress架构,可以通过扩展REST API来实现多语言支持:
// 示例:扩展WordPress REST API支持多语言
class Multilingual_REST_API {
public function __construct() {
add_action('rest_api_init', [$this, 'register_routes']);
add_filter('rest_prepare_post', [$this, 'add_translations_to_response'], 10, 3);
add_filter('rest_prepare_product', [$this, 'add_translations_to_response'], 10, 3);
}
public function register_routes() {
// 注册语言端点
register_rest_route('multilingual/v1', '/languages', [
'methods' => 'GET',
'callback' => [$this, 'get_available_languages'],
'permission_callback' => '__return_true'
]);
// 注册翻译端点
register_rest_route('multilingual/v1', '/translate', [
'methods' => 'POST',
'callback' => [$this, 'translate_content'],
'permission_callback' => function() {
return current_user_can('edit_posts');
}
]);
// 多语言产品搜索
register_rest_route('multilingual/v1', '/products/search', [
'methods' => 'GET',
'callback' => [$this, 'search_products_multilingual'],
'args' => [
'query' => [
'required' => true,
'validate_callback' => function($param) {
return !empty($param);
}
],
'lang' => [
'default' => 'en',
'validate_callback' => function($param) {
return in_array($param, $this->get_available_language_codes());
}
]
],
'permission_callback' => '__return_true'
]);
}
public function add_translations_to_response($response, $post, $request) {
$lang = $request->get_param('lang') ?: $this->detect_language_from_request($request);
if ($lang !== $this->get_default_language()) {
$translation = $this->get_post_translation($post->ID, $lang);
if ($translation) {
$response->data['title']['rendered'] = $translation['title'];
$response->data['content']['rendered'] = $translation['content'];
$response->data['excerpt']['rendered'] = $translation['excerpt'];
// 添加翻译元数据
$response->data['multilingual'] = [
'original_id' => $post->ID,
'language' => $lang,
'translated_at' => $translation['translated_at']
];
}
}
// 添加可用翻译链接
$response->data['available_translations'] = $this->get_post_translation_links($post->ID);
return $response;
}
public function search_products_multilingual($request) {
$query = sanitize_text_field($request['query']);
$lang = sanitize_text_field($request['lang']);
// 根据语言搜索
if ($lang === $this->get_default_language()) {
$args = [
'post_type' => 'product',
's' => $query,
'posts_per_page' => 10,
'lang' => $lang
];
} else {
// 在翻译内容中搜索
$args = [
'post_type' => 'product',
'meta_query' => [
'relation' => 'OR',
[
'key' => '_translation_title_' . $lang,
'value' => $query,
'compare' => 'LIKE'
],
[
'key' => '_translation_content_' . $lang,
'value' => $query,
'compare' => 'LIKE'
]
],
'posts_per_page' => 10
];
}
$products = get_posts($args);
// 格式化响应
$formatted_products = array_map(function($product) use ($lang) {
$product_data = $this->get_product_data_for_language($product, $lang);
return [
'id' => $product->ID,
'title' => $product_data['title'],
'description' => wp_trim_words($product_data['description'], 30),
'price' => get_post_meta($product->ID, '_price', true),
'image' => get_the_post_thumbnail_url($product->ID, 'thumbnail'),
'url' => $this->get_product_url_for_language($product->ID, $lang),
'language' => $lang
];
}, $products);
return rest_ensure_response([
'query' => $query,
'language' => $lang,
'results' => $formatted_products,
'count' => count($formatted_products)
]);
}
}
### 前端多语言状态管理(React示例)
// 前端多语言上下文和状态管理
import React, { createContext, useContext, useReducer, useEffect } from 'react';
import axios from 'axios';
// 创建多语言上下文
const MultilingualContext = createContext();
// 初始状态
const initialState = {
currentLanguage: localStorage.getItem('preferredLanguage') || 'en',
availableLanguages: [],
translations: {},
isLoading: false,
error: null
};
// 动作类型
const actionTypes = {
SET_LANGUAGE: 'SET_LANGUAGE',
SET_TRANSLATIONS: 'SET_TRANSLATIONS',
SET_AVAILABLE_LANGUAGES: 'SET_AVAILABLE_LANGUAGES',
SET_LOADING: 'SET_LOADING',
SET_ERROR: 'SET_ERROR'
};
// reducer函数
function multilingualReducer(state, action) {
switch (action.type) {
case actionTypes.SET_LANGUAGE:
localStorage.setItem('preferredLanguage', action.payload);
return {
...state,
currentLanguage: action.payload
};
case actionTypes.SET_TRANSLATIONS:
return {
...state,
translations: {
...state.translations,
[action.payload.language]: action.payload.translations
}
};
case actionTypes.SET_AVAILABLE_LANGUAGES:
return {
...state,
availableLanguages: action.payload
};
case actionTypes.SET_LOADING:
return {
...state,
isLoading: action.payload
};
case actionTypes.SET_ERROR:
return {
...state,
error: action.payload
};
default:
return state;
}
}
// 多语言提供者组件
export function MultilingualProvider({ children, apiEndpoint }) {
const [state, dispatch] = useReducer(multilingualReducer, initialState);
// 加载可用语言
useEffect(() => {
const fetchLanguages = async () => {
try {
dispatch({ type: actionTypes.SET_LOADING, payload: true });
const response = await axios.get(`${apiEndpoint}/multilingual/v1/languages`);
dispatch({
type: actionTypes.SET_AVAILABLE_LANGUAGES,
payload: response.data
});
} catch (error) {
dispatch({
type: actionTypes.SET_ERROR,
payload: error.message
});
} finally {
dispatch({ type: actionTypes.SET_LOADING, payload: false });
}
};
fetchLanguages();
}, [apiEndpoint]);
// 切换语言
const switchLanguage = async (languageCode) => {
dispatch({ type: actionTypes.SET_LANGUAGE, payload: languageCode });
// 预加载翻译
if (!state.translations[languageCode]) {
await loadTranslations(languageCode);
}
};
// 加载翻译
const loadTranslations = async (languageCode) => {
try {
dispatch({ type: actionTypes.SET_LOADING, payload: true });
const response = await axios.get(
`${apiEndpoint}/multilingual/v1/translations/${languageCode}`
);
dispatch({
type: actionTypes.SET_TRANSLATIONS,
payload: {
language: languageCode,
translations: response.data
}
});
} catch (error) {
dispatch({
type: actionTypes.SET_ERROR,
payload: error.message
});
} finally {
dispatch({ type: actionTypes.SET_LOADING, payload: false });
}
};
// 翻译函数
const t = (key, params = {}) => {
const translations = state.translations[state.currentLanguage] || {};
let text = translations[key] || key;
// 替换参数
Object.keys(params).forEach(param => {
text = text.replace(`{{${param}}}`, params[param]);
});
return text;
};
const value = {
...state,
switchLanguage,
t,
loadTranslations
};
return (
<MultilingualContext.Provider value={value}>
{children}
</MultilingualContext.Provider>
);
}
// 使用钩子
export function useMultilingual() {
const context = useContext(MultilingualContext);
if (!context) {
throw new Error('useMultilingual must be used within MultilingualProvider');
}
return context;
}
// 语言切换器组件
export function LanguageSwitcher() {
const { currentLanguage, availableLanguages, switchLanguage } = useMultilingual();
return (
<div className="language-switcher">
{availableLanguages.map(language => (
<button
key={language.code}
className={`language-button ${currentLanguage === language.code ? 'active' : ''}`}
onClick={() => switchLanguage(language.code)}
aria-label={`Switch to ${language.name}`}
>
<span className="language-flag">{language.flag}</span>
<span className="language-name">{language.name}</span>
</button>
))}
</div>
);
}
### 静态生成与ISR策略
// Next.js示例:多语言静态生成
export async function getStaticPaths() {
// 获取所有支持的语言
const languages = await fetchLanguages();
// 获取所有产品
const products = await fetchAllProducts();
// 为每种语言和每个产品生成路径
const paths = [];
languages.forEach(language => {
products.forEach(product => {
paths.push({
params: {
lang: language.code,
slug: product.slug
}
});
});
});
return {
paths,
fallback: 'blocking' // 增量静态再生
};
}
export async function getStaticProps({ params }) {
const { lang, slug } = params;
// 获取产品数据(根据语言)
const product = await fetchProductBySlug(slug, lang);
if (!product) {
return {
notFound: true
};
}
// 获取相关翻译
const translations = await fetchProductTranslations(product.id);
// 获取语言信息
const languages = await fetchLanguages();
return {
props: {
product,
translations,
currentLanguage: lang,
languages
},
revalidate: 3600 // 每小时重新验证
};
}
// 产品页面组件
function ProductPage({ product, translations, currentLanguage, languages }) {
const { t } = useTranslation();
return (
<div>
<Head>
<title>{product.title} | {t('store_name')}</title>
{/* 添加hreflang标签 */}
{languages.map(lang => (
<link
key={lang.code}
rel="alternate"
hrefLang={lang.code}
href={`https://example.com/${lang.code}/products/${product.slug}`}
/>
))}
</Head>
<LanguageSwitcher languages={languages} currentLanguage={currentLanguage} />
<h1>{product.title}</h1>
<div dangerouslySetInnerHTML={{ __html: product.description }} />
<ProductPrice
price={product.price}
currency={getCurrencyForLanguage(currentLanguage)}
/>
<AddToCartButton
productId={product.id}
language={currentLanguage}
/>
</div>
);
}
