如何在Django CMS的i18n_patterns中为语言Slug添加地域前缀并保留原有语言设置?
如何在Django CMS的i18n_patterns中为语言Slug添加域名相关前缀?
这个需求完全可行,而且不需要修改现有的LANGUAGES配置——我们只需要在URL解析和生成层面做一层前缀映射,让自定义前缀(比如ch-de)对应到原有的语言代码(比如de)即可,这样CMS、modeltranslation等依赖原有语言配置的模块完全不受影响。
下面是具体的实现步骤:
1. 配置域名与前缀的映射关系
首先在settings.py中添加域名到自定义前缀的映射,以及反向的前缀到语言代码的映射:
# settings.py # 域名 -> 自定义语言前缀 DOMAIN_LANGUAGE_PREFIX = { "example.ch": "ch-de", "example.us": "us-en", "example.fr": "fr-fr", # 按需添加其他域名 } # 反向映射:自定义前缀 -> 原语言代码 PREFIX_TO_LANGUAGE = {v: k.split("-")[1] for k, v in DOMAIN_LANGUAGE_PREFIX.items()}
同时确保你已经启用了django.contrib.sites应用(Django CMS通常已经依赖它),并在后台为每个域名创建对应的Site实例。
2. 自定义语言前缀模式
我们需要替换Django默认的LocalePrefixPattern,让它根据当前站点的域名生成对应的自定义前缀。在项目的urls.py中添加以下代码:
# urls.py from django.conf import settings from django.conf.urls.i18n import LocalePrefixPattern from django.urls import path, include from django.contrib.sites.models import Site class DomainLocalePrefixPattern(LocalePrefixPattern): def __init__(self): # 根据你的需求设置是否为默认语言添加前缀 super().__init__(prefix_default_language=False) @property def prefix(self): # 获取当前站点的域名 current_site = Site.objects.get_current() # 匹配对应的自定义前缀,默认用原语言代码兜底 custom_prefix = settings.DOMAIN_LANGUAGE_PREFIX.get(current_site.domain, self.language_code) return f"{custom_prefix}/" def reverse(self, viewname, args=None, kwargs=None, current_app=None): # 生成URL时替换默认语言前缀为自定义前缀 original_url = super().reverse(viewname, args, kwargs, current_app) current_site = Site.objects.get_current() custom_prefix = settings.DOMAIN_LANGUAGE_PREFIX.get(current_site.domain, self.language_code) return original_url.replace(f"/{self.language_code}/", f"/{custom_prefix}/", 1) # 自定义i18n_patterns函数,使用我们的前缀模式 def domain_i18n_patterns(*args, **kwargs): pattern = DomainLocalePrefixPattern() return [path(pattern, include(args))]
3. 替换URL配置中的i18n_patterns
把原来urls.py中的i18n_patterns替换为我们自定义的domain_i18n_patterns:
# urls.py urlpatterns = [ # 这里放不需要国际化的URL,比如admin、static等 path("admin/", admin.site.urls), ] + domain_i18n_patterns( # 这里放所有需要国际化的URL,包括Django CMS的URL path("", include("cms.urls")), # 其他应用的国际化URL也放在这里 )
4. 自定义Locale中间件解析前缀
我们需要让Django能识别自定义前缀,并映射到正确的语言代码。创建一个middleware.py文件,添加以下中间件:
# middleware.py from django.conf import settings from django.middleware.locale import LocaleMiddleware class DomainLocaleMiddleware(LocaleMiddleware): def process_request(self, request): # 从URL路径中提取第一个部分(自定义前缀) path_parts = request.path_info.lstrip("/").split("/") if path_parts and path_parts[0]: custom_prefix = path_parts[0] # 检查是否是我们配置的前缀 language_code = settings.PREFIX_TO_LANGUAGE.get(custom_prefix) if language_code: # 设置正确的语言代码 request.LANGUAGE_CODE = language_code # 移除前缀,让后续URL解析正常工作 request.path_info = "/" + "/".join(path_parts[1:]) # 调用父类方法完成剩余的语言处理逻辑 super().process_request(request)
然后在settings.py中替换默认的LocaleMiddleware:
# settings.py MIDDLEWARE = [ # 保持其他中间件顺序不变,替换LocaleMiddleware # ... 其他中间件 ... "your_project.middleware.DomainLocaleMiddleware", # 替换 django.middleware.locale.LocaleMiddleware # ... 其他中间件 ... ]
5. 测试验证
完成以上配置后,你可以:
- 访问
https://example.ch/ch-de/your-page/,系统会识别语言为de,并加载对应的CMS内容 - 调用
reverse生成URL时,会自动根据当前域名生成对应的自定义前缀 - 所有依赖
LANGUAGE_CODE和LANGUAGES配置的模块(比如modeltranslation、CMS)都能正常工作,因为我们没有修改核心的语言配置
这样就完美实现了你的需求:URL使用带域名前缀的语言slug,但系统内部仍使用原语言代码,完全兼容现有内容体系。
内容的提问来源于stack exchange,提问作者benzkji
相关产品推荐
相关产品推荐

