/// <summary>Uses a standard <see cref="ResourceManager"/> object to obtain translations.</summary> /// <param name="manager">A ResourceManager that provides access to resources (resx embedded in an assembly)</param> /// <param name="culture">A value of <see cref="CultureInfo"/> that /// represents the language to look up in the ResourceManager. If this is /// null, the ResourceManager will use CultureInfo.CurrentUICulture.</param> /// <param name="resxNameCalculator">An optional function that will be /// called when a translation is requested without providing a resource /// key symbol. For example, if someone writes <c>"Save as...".Localized()</c> /// using the <see cref="Localized(string)"/> extension method, this /// function is called on the string "Save as...". This function could /// be used to compute a resource name such as "strSaveAs" automatically, /// according to whatever naming convention is used in your resource file. /// </param> /// <param name="fallbackToPrevious">If a translation was not found in the /// specified ResourceManager and this parameter is true, the previously- /// installed <see cref="Localizer"/> is called instead. Otherwise, the /// dummy translator <see cref="Passthru"/> is used.</param> /// <returns></returns> public static SavedValue <LocalizerDelegate> UseResourceManager(ResourceManager manager, CultureInfo culture = null, Func <string, string> resxNameCalculator = null, bool fallbackToPrevious = true) { CheckParam.IsNotNull("manager", manager); LocalizerDelegate fallback = (fallbackToPrevious ? Localizer : null) ?? Passthru; return(SetLocalizer((Symbol resourceId, string defaultMessage) => { string id; if (resourceId != null) { id = resourceId.Name; } else { id = (resxNameCalculator != null ? resxNameCalculator(defaultMessage) : null) ?? defaultMessage; } var translation = manager.GetString(id, culture); if (translation != null) { return translation; } else { return fallback(resourceId, defaultMessage); } })); }
/// <summary>Sets the localizer method.</summary> /// <remarks><see cref="Localizer"/> is a thread-local value, but since /// .NET does not support inheritance of thread-local values, this method /// also sets the global default used by threads on which this method was /// never called. /// <para/> /// This property follows the Ambient Service Pattern: /// http://core.loyc.net/essentials/ambient-service-pattern.html /// </remarks> public static SavedValue<LocalizerDelegate> SetLocalizer(LocalizerDelegate newValue) { return new SavedValue<LocalizerDelegate>(_localizer, newValue ?? Passthru); }
/// <summary>Sets the localizer method.</summary> /// <remarks><see cref="Localizer"/> is a thread-local value, but since /// .NET does not support inheritance of thread-local values, this method /// also sets the global default used by threads on which this method was /// never called. /// <para/> /// This property follows the Ambient Service Pattern: /// http://core.loyc.net/essentials/ambient-service-pattern.html /// </remarks> public static SavedValue <LocalizerDelegate> SetLocalizer(LocalizerDelegate newValue) { return(new SavedValue <LocalizerDelegate>(_localizer, newValue ?? Passthru)); }
/// <summary> /// Traverse the input object recursively and execute the localizer method on all properties of type DateTime. All elements of arrays and collections that implement an 'int' /// indexer will be examined. /// </summary> /// <param name="obj">Object to traverse</param> /// <param name="localizer">Method to perform the localization on the DateTime properties</param> /// <returns>Traversed object</returns> public object TraverseObject(object obj, LocalizerDelegate localizer) { if (null == obj) { return null; } var objectType = obj.GetType(); if (typeof (DateTime) == objectType) { return localizer((DateTime) obj); } if (objectType.IsArray) { var array = (Array) obj; for (int i = 0; i < array.Length; i++) { var element = array.GetValue(i); var localizedObject = this.TraverseObject(element, localizer); array.SetValue(localizedObject, i); } return obj; } if (objectType.HasIndexer<int>()) { var listType = objectType.GetGenericArguments() .FirstOrDefault(); if (null == listType) { return obj; } try { int i = 0; while (true) { var indexer = objectType.GetIndexer<int>(); var indexValue = indexer.GetValue(obj, new object[] { i }); var localizedObject = this.TraverseObject(indexValue, localizer); indexer.SetValue(obj, localizedObject, new object[] { i }); i++; } } catch (TargetInvocationException ex) { if (false == (ex.InnerException is ArgumentOutOfRangeException)) { throw; } // The index of the collection was exceeded and execution can continue traversing the properties. } return obj; } if (true == objectType.IsSerializable) { return obj; } var properties = objectType.GetProperties(); foreach (var prop in properties) { if ((false == prop.CanWrite) || (null != prop.GetCustomAttribute<LocalizerIgnoreAttribute>())) { continue; } var value = prop.GetValue(obj, null); if (value == null) { continue; } var localizedObject = this.TraverseObject(value, localizer); prop.SetValue(obj, localizedObject, null); } return obj; }