Skip to Content
🎉 探索 Shopify 的无限可能 结构化知识 + 实战案例,持续更新中...
Liquid 开发多语言和本地化

多语言和本地化

在全球化的电商环境中,多语言支持是必不可少的功能。Shopify 提供了强大的多语言和本地化功能,让您能够为不同地区的客户提供本地化的购物体验。

基础多语言设置

语言检测

<!-- 当前语言信息 --> <div class="language-info" data-current-locale="{{ request.locale.iso_code }}"> <p>当前语言: {{ request.locale.name }}</p> <p>语言代码: {{ request.locale.iso_code }}</p> <p>根URL: {{ request.locale.root_url }}</p> </div> <!-- 语言切换器 --> <div class="language-switcher"> <label for="language-select">选择语言:</label> <select id="language-select" onchange="switchLanguage(this.value)"> {% for locale in shop.published_locales %} <option value="{{ locale.iso_code }}" {% if locale.iso_code == request.locale.iso_code %}selected{% endif %}> {{ locale.name }} </option> {% endfor %} </select> </div> <script> function switchLanguage(localeCode) { const currentUrl = window.location.pathname + window.location.search window.location.href = `/${localeCode}${currentUrl}` } </script>

文本翻译

<!-- 基本文本翻译 --> <div class="site-navigation"> <a href="{{ routes.root_url }}">{{ 'general.navigation.home' | t }}</a> <a href="{{ routes.all_products_collection_url }}">{{ 'general.navigation.catalog' | t }}</a> <a href="{{ routes.cart_url }}"> {{ 'general.navigation.cart' | t }} ({{ cart.item_count }}) </a> <a href="/pages/about">{{ 'general.navigation.about' | t }}</a> <a href="/pages/contact">{{ 'general.navigation.contact' | t }}</a> </div> <!-- 带参数的翻译 --> <div class="product-price"> {% assign discount_percentage = product.compare_at_price | minus: product.price | times: 100 | divided_by: product.compare_at_price %} <span class="original-price"> {{ 'products.product.original_price' | t: price: product.compare_at_price | money }} </span> <span class="sale-price"> {{ 'products.product.sale_price' | t: price: product.price | money }} </span> <span class="discount"> {{ 'products.product.save_percentage' | t: percentage: discount_percentage }} </span> </div>

货币本地化

货币格式

<!-- 货币显示 --> <div class="currency-display"> <div class="price-primary"> {{ product.price | money_with_currency }} </div> <div class="price-local"> {{ product.price | money: request.locale.currency.symbol }} </div> <!-- 多货币支持 --> {% if shop.enabled_currencies.size > 1 %} <div class="currency-selector"> <select onchange="changeCurrency(this.value)"> {% for currency in shop.enabled_currencies %} <option value="{{ currency.iso_code }}" {% if currency.iso_code == cart.currency.iso_code %}selected{% endif %}> {{ currency.name }} ({{ currency.symbol }}) </option> {% endfor %} </select> </div> {% endif %} </div> <script> function changeCurrency(currencyCode) { fetch('/cart/update.js', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ currency: currencyCode }) }).then(() => { location.reload() }) } </script>

价格格式化

<!-- 自定义价格格式 --> {% capture price_format %} {% case request.locale.iso_code %} {% when 'zh-CN' %} ¥{{ price | divided_by: 100.0 | round: 2 }} {% when 'ja' %} ¥{{ price | divided_by: 100.0 | round: 0 }} {% when 'en-US' %} ${{ price | divided_by: 100.0 | round: 2 }} {% when 'en-GB' %} £{{ price | divided_by: 100.0 | round: 2 }} {% else %} {{ price | money }} {% endcase %} {% endcapture %} <div class="localized-price">{{ price_format }}</div>

日期和时间本地化

日期格式

<!-- 本地化日期显示 --> <div class="date-display"> {% case request.locale.iso_code %} {% when 'zh-CN' %} <time>{{ article.published_at | date: '%Y年%m月%d日' }}</time> {% when 'en-US' %} <time>{{ article.published_at | date: '%B %d, %Y' }}</time> {% when 'en-GB' %} <time>{{ article.published_at | date: '%d %B %Y' }}</time> {% when 'ja' %} <time>{{ article.published_at | date: '%Y年%m月%d日' }}</time> {% else %} <time>{{ article.published_at | date: '%Y-%m-%d' }}</time> {% endcase %} </div> <!-- 相对时间 --> <div class="relative-time"> {% assign days_ago = 'now' | date: '%s' | minus: article.published_at | date: '%s' | divided_by: 86400 %} {% if days_ago == 0 %} {{ 'general.date.today' | t }} {% elsif days_ago == 1 %} {{ 'general.date.yesterday' | t }} {% elsif days_ago < 7 %} {{ 'general.date.days_ago' | t: count: days_ago }} {% else %} {{ article.published_at | date: '%Y-%m-%d' }} {% endif %} </div>

地址格式化

本地化地址

<!-- 地址格式本地化 --> <address class="localized-address"> {% case request.locale.iso_code %} {% when 'zh-CN' %} <!-- 中文地址格式 --> <div class="address-country">{{ address.country }}</div> <div class="address-province">{{ address.province }}</div> <div class="address-city">{{ address.city }}</div> <div class="address-street">{{ address.address1 }}</div> {% if address.address2 %} <div class="address-street2">{{ address.address2 }}</div> {% endif %} <div class="address-zip">{{ address.zip }}</div> <div class="address-name">{{ address.first_name }} {{ address.last_name }}</div> {% when 'ja' %} <!-- 日文地址格式 --> <div class="address-zip">〒{{ address.zip }}</div> <div class="address-country">{{ address.country }}</div> <div class="address-province">{{ address.province }}</div> <div class="address-city">{{ address.city }}</div> <div class="address-street">{{ address.address1 }}</div> {% if address.address2 %} <div class="address-street2">{{ address.address2 }}</div> {% endif %} <div class="address-name">{{ address.last_name }} {{ address.first_name }}</div> {% else %} <!-- 西方地址格式 --> <div class="address-name">{{ address.first_name }} {{ address.last_name }}</div> <div class="address-street">{{ address.address1 }}</div> {% if address.address2 %} <div class="address-street2">{{ address.address2 }}</div> {% endif %} <div class="address-city-state"> {{ address.city }}, {{ address.province }} {{ address.zip }} </div> <div class="address-country">{{ address.country }}</div> {% endcase %} </address>

内容本地化

产品信息本地化

<!-- 本地化产品内容 --> <div class="product-info"> <h1>{{ product.title }}</h1> <!-- 本地化描述 --> {% assign localized_description = product.metafields.translations[request.locale.iso_code].description %} {% if localized_description %} <div class="product-description">{{ localized_description }}</div> {% else %} <div class="product-description">{{ product.description }}</div> {% endif %} <!-- 本地化特性列表 --> {% assign features_key = 'features_' | append: request.locale.iso_code %} {% assign localized_features = product.metafields.custom[features_key] %} {% if localized_features %} <div class="product-features"> <h3>{{ 'products.product.features' | t }}</h3> <ul> {% for feature in localized_features %} <li>{{ feature }}</li> {% endfor %} </ul> </div> {% endif %} </div>

集合本地化

<!-- 本地化集合信息 --> <div class="collection-header"> {% assign localized_title = collection.metafields.translations[request.locale.iso_code].title %} <h1>{% if localized_title %}{{ localized_title }}{% else %}{{ collection.title }}{% endif %}</h1> {% assign localized_description = collection.metafields.translations[request.locale.iso_code].description %} {% if localized_description %} <div class="collection-description">{{ localized_description }}</div> {% elsif collection.description %} <div class="collection-description">{{ collection.description }}</div> {% endif %} </div>

SEO 本地化

hreflang 标签

<!-- hreflang 实现 --> <head> {% for locale in shop.published_locales %} <link rel="alternate" hreflang="{{ locale.iso_code }}" href="{{ locale.root_url }}{{ request.path }}"> {% endfor %} <!-- 默认语言 --> <link rel="alternate" hreflang="x-default" href="{{ shop.primary_locale.root_url }}{{ request.path }}"> </head>

本地化 meta 标签

<!-- 本地化 SEO 标签 --> <head> {% assign page_title_key = 'meta.title.' | append: template %} {% assign page_description_key = 'meta.description.' | append: template %} <title> {% if page_title_key != blank %} {{ page_title_key | t: shop_name: shop.name, page_title: page_title }} {% else %} {{ page_title }}{% unless page_title contains shop.name %} - {{ shop.name }}{% endunless %} {% endif %} </title> <meta name="description" content="{{ page_description_key | t | default: page_description | truncate: 160 }}"> <!-- Open Graph 本地化 --> <meta property="og:locale" content="{{ request.locale.iso_code | replace: '-', '_' }}"> {% for locale in shop.published_locales %} {% unless locale.iso_code == request.locale.iso_code %} <meta property="og:locale:alternate" content="{{ locale.iso_code | replace: '-', '_' }}"> {% endunless %} {% endfor %} </head>

RTL 支持

右到左语言支持

<!-- RTL 语言支持 --> {% assign rtl_languages = 'ar,he,fa,ur' | split: ',' %} {% assign is_rtl = false %} {% for rtl_lang in rtl_languages %} {% if request.locale.iso_code contains rtl_lang %} {% assign is_rtl = true %} {% break %} {% endif %} {% endfor %} <html dir="{% if is_rtl %}rtl{% else %}ltr{% endif %}" lang="{{ request.locale.iso_code }}"> <head> <style> {% if is_rtl %} body { direction: rtl; text-align: right; } .container { padding-right: 20px; padding-left: 20px; } .navigation { float: right; } .breadcrumbs { direction: rtl; } .breadcrumbs::before { content: "←"; margin-left: 5px; margin-right: 0; } {% endif %} </style> </head>

表单本地化

多语言表单

<!-- 本地化表单 --> <form action="/contact" method="post" class="contact-form"> <div class="form-group"> <label for="contact-name">{{ 'contact.form.name' | t }}</label> <input type="text" id="contact-name" name="contact[name]" placeholder="{{ 'contact.form.name_placeholder' | t }}" required> </div> <div class="form-group"> <label for="contact-email">{{ 'contact.form.email' | t }}</label> <input type="email" id="contact-email" name="contact[email]" placeholder="{{ 'contact.form.email_placeholder' | t }}" required> </div> <div class="form-group"> <label for="contact-subject">{{ 'contact.form.subject' | t }}</label> <select id="contact-subject" name="contact[subject]"> <option value="">{{ 'contact.form.subject_choose' | t }}</option> <option value="general">{{ 'contact.form.subject_general' | t }}</option> <option value="support">{{ 'contact.form.subject_support' | t }}</option> <option value="wholesale">{{ 'contact.form.subject_wholesale' | t }}</option> </select> </div> <div class="form-group"> <label for="contact-message">{{ 'contact.form.message' | t }}</label> <textarea id="contact-message" name="contact[body]" placeholder="{{ 'contact.form.message_placeholder' | t }}" required></textarea> </div> <button type="submit" class="btn btn-primary"> {{ 'contact.form.send' | t }} </button> </form>

本地化工具

翻译文件结构

<!-- 翻译文件路径检查 --> {% comment %} 翻译文件位置: /locales/en.default.json /locales/zh-CN.json /locales/ja.json /locales/fr.json {% endcomment %} <!-- 翻译键检查 --> <div class="translation-debug" style="display: none;"> {% assign test_keys = 'general.navigation.home,products.product.add_to_cart,cart.general.title' | split: ',' %} {% for key in test_keys %} <p>{{ key }}: "{{ key | t }}"</p> {% endfor %} </div>

翻译管理

<!-- 翻译管理助手 --> {% if request.design_mode %} <div class="translation-helper" style="position: fixed; top: 10px; right: 10px; background: #fff; padding: 10px; border: 1px solid #ccc; z-index: 9999;"> <h4>翻译助手</h4> <p><strong>当前语言:</strong> {{ request.locale.name }} ({{ request.locale.iso_code }})</p> <p><strong>可用语言:</strong></p> <ul> {% for locale in shop.published_locales %} <li> <a href="{{ locale.root_url }}{{ request.path }}"> {{ locale.name }} ({{ locale.iso_code }}) </a> </li> {% endfor %} </ul> </div> {% endif %}

性能优化

本地化缓存

<script> // 翻译缓存 const TranslationCache = { cache: {}, get: function(key, locale = null) { const currentLocale = locale || document.documentElement.lang const cacheKey = `${currentLocale}.${key}` if (this.cache[cacheKey]) { return this.cache[cacheKey] } // 从服务器获取翻译 return this.fetch(key, currentLocale) }, fetch: function(key, locale) { return fetch(`/locales/${locale}.json`) .then(response => response.json()) .then(translations => { const value = this.getNestedValue(translations, key) this.cache[`${locale}.${key}`] = value return value }) }, getNestedValue: function(obj, path) { return path.split('.').reduce((o, p) => o && o[p], obj) } } // 动态翻译 function t(key, params = {}) { return TranslationCache.get(key).then(translation => { if (typeof translation === 'string') { // 替换参数 Object.keys(params).forEach(param => { translation = translation.replace(new RegExp(`{{\\s*${param}\\s*}}`, 'g'), params[param]) }) } return translation || key }) } </script>

测试和调试

本地化测试

<!-- 本地化测试工具 --> {% if request.design_mode %} <div class="localization-test" style="margin: 20px 0; padding: 20px; background: #f8f9fa; border: 1px solid #dee2e6;"> <h3>本地化测试</h3> <div class="test-section"> <h4>语言信息</h4> <ul> <li>当前语言: {{ request.locale.name }} ({{ request.locale.iso_code }})</li> <li>默认语言: {{ shop.primary_locale.name }} ({{ shop.primary_locale.iso_code }})</li> <li>可用语言数: {{ shop.published_locales.size }}</li> </ul> </div> <div class="test-section"> <h4>货币信息</h4> <ul> <li>当前货币: {{ cart.currency.iso_code }}</li> <li>货币符号: {{ cart.currency.symbol }}</li> <li>可用货币数: {{ shop.enabled_currencies.size }}</li> </ul> </div> <div class="test-section"> <h4>翻译测试</h4> <p>导航.首页: {{ 'general.navigation.home' | t }}</p> <p>产品.加入购物车: {{ 'products.product.add_to_cart' | t }}</p> <p>购物车.标题: {{ 'cart.general.title' | t }}</p> </div> </div> {% endif %}

下一步学习

现在您已经掌握了多语言和本地化功能,建议继续学习:

最后更新时间: