• (5) Orchard 开发之 Localization and NullLocalizer


      大家都知道在 orchard 中做国际化的时候,直接在代码或 view 中用 T 包上要进行国际化得字符串就行了,

    之后 orchard 就会根据你设置得语言文化,寻找到相应得 po 文件来进行 localization。

    在 Controller 中你通常定义一个属性,public Localizer T { get; set; } 这里 T 是一个委托。

    之后在构造函数中注入一个 NullLocalizer.Instance ,但当你打开 NullLocalizer 时,你发现这个类并没有做什么具体的工作,那国际化究竟是怎么做的呢?

    事实上你删掉构造函数中的  T = NullLocalizer.Instance; 不会有任何问题,我也不知道 NullLocalizer 有什么用处??

    public static class NullLocalizer {
            
            static NullLocalizer () {
                _instance = (format, args) => new LocalizedString((args == null || args.Length == 0) ? format : string.Format(format, args));
            }
            
            static readonly Localizer _instance;
    
            public static Localizer Instance { get { return _instance; } }
        }

    下面让我们看看 orchard 中国际化是怎么做的:

    具体的类都定义在 Orchard.Framework\Localization\ 下面

    首先来看 LocalizationModule 类:

    protected override void Load(ContainerBuilder builder) {
                builder.RegisterType<Text>().As<IText>().InstancePerDependency();
            }
    
            protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
               // 通过反射 ,查看你是否定义个一个 public 的 ,名字叫 T 的 ,类型为 Localizer 的委托 
               // 所以 T 必须是 public 的 名字也不能随便变 
            var userProperty = FindUserProperty(registration.Activator.LimitType);  
                if (userProperty != null) {
                    var scope = registration.Activator.LimitType.FullName;
    
                    registration.Activated += (sender, e) => {    // 这里给   registration 这个事件注册了很多个方法
                        var localizer = _localizerCache.GetOrAdd(scope, key => LocalizationUtilities.Resolve(e.Context, scope)); // 得到一个 Localizer 对象
                        userProperty.SetValue(e.Instance, localizer, null); // 把得到的 Localizer 对象赋给 T ,实际传入的是 Text 类中 Get 方法
                        // 实际上 AdminMenu 的 T 也是在这里绑定的, 当你需要一个 Localizer  的实例时这个事件就会被触发,给你的 T 绑定一个方法 (Get)
                    };
                }
            }
    
            private static PropertyInfo FindUserProperty(Type type) {
                return type.GetProperty("T", typeof(Localizer));
            }

    下面我们来看看 Text 中的 Get 方法,这才是 T 实际绑定的方法

    public LocalizedString Get(string textHint, params object[] args) {   // textHint 就是 T 包裹的字符串
                Logger.Debug("{0} localizing '{1}'", _scope, textHint);
    
                var workContext = _workContextAccessor.GetContext();
                var currentCulture = workContext.CurrentCulture;  // 得到当前的语言文化,第一次会从数据库中的 Settings_SiteSettingsPartRecord 这个表中读取,随会缓存起来
    
               // 调用 DefaultLocalizedStringManager 中的 GetLocalizedString 方法返回一个本地化的字符串            
                var localizedFormat = _localizedStringManager.GetLocalizedString(_scope, textHint, currentCulture); 
                return args.Length == 0 
                    ? new LocalizedString(localizedFormat, _scope, textHint, args)// 把返回的字符串包装成 LocalizedString 对象,以便显示在页面上 
                    : new LocalizedString(string.Format(GetFormatProvider(currentCulture), localizedFormat, args), _scope, textHint, args);         
    }

    下面我们来看 DefaultLocalizedStringManager 中的 GetLocalizedString 方法

    public string GetLocalizedString(string scope, string text, string cultureName) {
                var culture = LoadCulture(cultureName); // 得到当前语言文化
    
                string scopedKey = (scope + "|" + text).ToLowerInvariant();
                if (culture.Translations.ContainsKey(scopedKey)) {
                    return culture.Translations[scopedKey];   // 如果当前 scope 中有 po 文件,直接取出翻译后的字符串
                }
    
                string genericKey = ("|" + text).ToLowerInvariant();
                if (culture.Translations.ContainsKey(genericKey)) {
                    return culture.Translations[genericKey];   // 当前工程中找不到 po 文件,再找其他地方,找到则取出翻译后的字符串
                }
    
                return GetParentTranslation(scope, text, cultureName);
            }

    orchard 中有一系列的查找路径去找到相应的 po 文件:

            const string CoreLocalizationFilePathFormat = "~/Core/App_Data/Localization/{0}/orchard.core.po";
            const string ModulesLocalizationFilePathFormat = "~/Modules/{0}/App_Data/Localization/{1}/orchard.module.po";
            const string ThemesLocalizationFilePathFormat = "~/Themes/{0}/App_Data/Localization/{1}/orchard.theme.po";
            const string RootLocalizationFilePathFormat = "~/App_Data/Localization/{0}/orchard.root.po";
            const string TenantLocalizationFilePathFormat = "~/App_Data/Sites/{0}/Localization/{1}/orchard.po";

    而且 orchard 中做国际化也非常方便:

    1) 在要需要国际化的类中定义一个叫 T 的委托  public Localizer T { get; set; }  (view 中直接用 T 包裹就行)

    2) 用 T 包裹需要本地化的字符串。

    3) 准备好 po 文件,按照指定的格式书写,放到指定的位置,orchard 就能找到并取出了。 po 文件必须是 utf-8 编码,否则会出现乱码,orchard 会用 utf-8 来解析 po 文件

    下面我简单翻译 BlogPostAdminController 中的两句提示信息:

    33

    把这个 po 文件放到 :\Modules\Orchard.Blogs\App_Data\Localization\zh-CN\orchard.module.po 就行了

    22    11

    有关 po 文件的格式 和 放置的地方请参考官方网站: http://docs.orchardproject.net/Documentation/Creating-global-ready-applications

  • 相关阅读:
    Java基础知识_毕向东_Java基础视频教程笔记(5-10 面向对象)
    Java 运算符-=,+=混合计算详解
    VS Code 基本介绍 和 快捷键
    Access-Control-Allow-Origin 跨域问题
    Linux常用命令收藏
    常用正则表达式
    IntelliJ IDEA 快捷键列表
    PAT A除以B
    PAT 部分A+B
    PAT 德才论
  • 原文地址:https://www.cnblogs.com/lesliefang/p/2861907.html
Copyright © 2020-2023  润新知