mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -26,12 +26,12 @@ msgstr "Bienvenue dans Orchard"
|
||||
#: ~/Core/Dashboard/Views/Admin/Index.ascx
|
||||
#| msgid : "The Orchard Team"
|
||||
msgid "The Orchard Team"
|
||||
msgstr "L'Equipe Orchard"
|
||||
msgstr "L'équipe Orchard"
|
||||
|
||||
#: ~/Core/Dashboard/Views/Admin/Index.ascx
|
||||
#| msgid : "This is the place where you can manage your web site, its appearance and its contents. Please take a moment to explore the different menu items on the left of the screen to familiarize yourself with the features of the application. For example, try to change the theme through the “Manage Themes” menu entry. You can also create new pages and manage existing ones through the “Manage Pages” menu entry or create blogs through “Manage Blogs”."
|
||||
msgid "This is the place where you can manage your web site, its appearance and its contents. Please take a moment to explore the different menu items on the left of the screen to familiarize yourself with the features of the application. For example, try to change the theme through the “Manage Themes” menu entry. You can also create new pages and manage existing ones through the “Manage Pages” menu entry or create blogs through “Manage Blogs”."
|
||||
msgstr "C'est l'endroit pour la gestion de votre site, son apparence et son contenu. Veuillez prendre votre temps explorer le menu à gauche de l'écran pour vous familiariser avec les aspects de l'application. Par exemple, essayez de changer le thème en utilisant le menu “Manage Themes”. Vous pouvez aussi créer de nouvelles pages et gérer les pages existantes via le menu “Manage Pages” ou bien créer des blogs via “Manage Blogs”."
|
||||
msgstr "Ceci est l'endroit où vous pouvez gérer votre site, son apparence et son contenu. Veuillez passer un instant à explorer le menu à gauche de l'écran pour vous familiariser avec les différents aspects de l'application. Par exemple, vous pouvez changer le thème en utilisant “Gérer les thèmes”. Vous pouvez également créer de nouvelles pages et gérer les pages existantes via “Gérer les pages” ou bien créer de nouveaux blogs via “Gérer les blogs”."
|
||||
|
||||
#: ~/Core/Dashboard/Views/Admin/Index.ascx
|
||||
#| msgid : "Have fun!"
|
||||
@@ -1801,7 +1801,7 @@ msgstr "Accès refusé"
|
||||
#: ~/Modules/Orchard.Users/Views/Account/AccessDenied.ascx
|
||||
#| msgid : "You do not have permission to complete your request."
|
||||
msgid "You do not have permission to complete your request."
|
||||
msgstr "Vous n'avez pas la permission de compléter votre requête"
|
||||
msgstr "Vous n'avez pas la permission de compléter cette requête."
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/ChangePassword.ascx
|
||||
#| msgid : "Change Password"
|
||||
@@ -1811,12 +1811,12 @@ msgstr "Changer le mot de passe"
|
||||
#: ~/Modules/Orchard.Users/Views/Account/ChangePassword.ascx
|
||||
#| msgid : "Use the form below to change your password."
|
||||
msgid "Use the form below to change your password."
|
||||
msgstr "Utilisez le forumulaire ci-dessous pour changer votre mot de passe."
|
||||
msgstr "Veuillez utiliser le forumulaire ci-dessous pour changer votre mot de passe."
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/ChangePassword.ascx
|
||||
#| msgid : "New passwords are required to be a minimum of {0} characters in length."
|
||||
msgid "New passwords are required to be a minimum of {0} characters in length."
|
||||
msgstr "Les mots de passe doivent contenir {0} charactères au minimum."
|
||||
msgstr "Les mots de passe doivent contenir au moins {0} caractères."
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/ChangePassword.ascx
|
||||
#| msgid : "Current password:"
|
||||
@@ -1856,7 +1856,7 @@ msgstr "La connexion a échoué. Veuillez corriger les erreurs et réessayer."
|
||||
#: ~/Modules/Orchard.Users/Views/Account/LogOn.ascx
|
||||
#| msgid : "Please enter your username and password."
|
||||
msgid "Please enter your username and password."
|
||||
msgstr "Veuillez saisir votre nom d'utilisateur et mot de passe."
|
||||
msgstr "Veuillez saisir votre nom d'utilisateur et votre mot de passe."
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/LogOn.ascx
|
||||
#| msgid : "Register"
|
||||
@@ -1871,7 +1871,7 @@ msgstr " si vous n'avez pas de compte."
|
||||
#: ~/Modules/Orchard.Users/Views/Account/LogOn.ascx
|
||||
#| msgid : "Account Information"
|
||||
msgid "Account Information"
|
||||
msgstr "Données de Compte"
|
||||
msgstr "Données du compte"
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/LogOn.ascx
|
||||
#| msgid : "Username or Email:"
|
||||
@@ -1886,7 +1886,7 @@ msgstr "Mot de passe:"
|
||||
#: ~/Modules/Orchard.Users/Views/Account/LogOn.ascx
|
||||
#| msgid : "Remember me?"
|
||||
msgid "Remember me?"
|
||||
msgstr "Souviens-moi?"
|
||||
msgstr "Se souvenir de moi?"
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/Register.ascx
|
||||
#| msgid : "Create a New Account"
|
||||
@@ -1896,12 +1896,12 @@ msgstr "Créer un nouveau compte utilisateur"
|
||||
#: ~/Modules/Orchard.Users/Views/Account/Register.ascx
|
||||
#| msgid : "Use the form below to create a new account."
|
||||
msgid "Use the form below to create a new account."
|
||||
msgstr "Utiliser le formulaire ci-dessous pour créer un nouveau compte."
|
||||
msgstr "Veuillez utiliser le formulaire ci-dessous pour créer un nouveau compte."
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/Register.ascx
|
||||
#| msgid : "Passwords are required to be a minimum of {0} characters in length."
|
||||
msgid "Passwords are required to be a minimum of {0} characters in length."
|
||||
msgstr "Les mots de passe doivent contenir {0} charactères au minimum."
|
||||
msgstr "Les mots de passe doivent contenir au moins {0} caractères."
|
||||
|
||||
#: ~/Modules/Orchard.Users/Views/Account/Register.ascx
|
||||
#| msgid : "Username:"
|
||||
@@ -1971,12 +1971,12 @@ msgstr "La connexion a échoué. Veuillez corriger les erreurs et réessayer."
|
||||
#: ~/Themes/Contoso/Views/LogOn.ascx
|
||||
#| msgid : "Please enter your username and password."
|
||||
msgid "Please enter your username and password."
|
||||
msgstr "Veuillez saisir votre nom d'utilisateur et mot de passe."
|
||||
msgstr "Veuillez saisir votre nom d'utilisateur et votre mot de passe."
|
||||
|
||||
#: ~/Themes/Contoso/Views/LogOn.ascx
|
||||
#| msgid : "Register"
|
||||
msgid "Register"
|
||||
msgstr "Enregistrer"
|
||||
msgstr "S'enregistrer"
|
||||
|
||||
#: ~/Themes/Contoso/Views/LogOn.ascx
|
||||
#| msgid : " if you don't have an account."
|
||||
@@ -1986,7 +1986,7 @@ msgstr " si vous n'avez pas de compte."
|
||||
#: ~/Themes/Contoso/Views/LogOn.ascx
|
||||
#| msgid : "Account Information"
|
||||
msgid "Account Information"
|
||||
msgstr "Données de Compte"
|
||||
msgstr "Données du Compte"
|
||||
|
||||
#: ~/Themes/Contoso/Views/LogOn.ascx
|
||||
#| msgid : "Username or Email:"
|
||||
@@ -2001,7 +2001,7 @@ msgstr "Mot de passe:"
|
||||
#: ~/Themes/Contoso/Views/LogOn.ascx
|
||||
#| msgid : "Remember me?"
|
||||
msgid "Remember me?"
|
||||
msgstr "Souviens-moi?"
|
||||
msgstr "Se souvenir de moi?"
|
||||
|
||||
#: ~/Themes/Contoso/Views/User.ascx
|
||||
#| msgid : "Log Off"
|
||||
@@ -2061,12 +2061,12 @@ msgstr "La connexion a échoué. Veuillez corriger les erreurs et réessayer."
|
||||
#: ~/Themes/Corporate/Views/LogOn.ascx
|
||||
#| msgid : "Please enter your username and password."
|
||||
msgid "Please enter your username and password."
|
||||
msgstr "Veuillez saisir votre nom d'utilisateur et mot de passe."
|
||||
msgstr "Veuillez saisir votre nom d'utilisateur et votre mot de passe."
|
||||
|
||||
#: ~/Themes/Corporate/Views/LogOn.ascx
|
||||
#| msgid : "Register"
|
||||
msgid "Register"
|
||||
msgstr "Enregistrer"
|
||||
msgstr "S'enregistrer"
|
||||
|
||||
#: ~/Themes/Corporate/Views/LogOn.ascx
|
||||
#| msgid : " if you don't have an account."
|
||||
@@ -2076,7 +2076,7 @@ msgstr " si vous n'avez pas de compte."
|
||||
#: ~/Themes/Corporate/Views/LogOn.ascx
|
||||
#| msgid : "Account Information"
|
||||
msgid "Account Information"
|
||||
msgstr "Données de Compte"
|
||||
msgstr "Données du Compte"
|
||||
|
||||
#: ~/Themes/Corporate/Views/LogOn.ascx
|
||||
#| msgid : "Username or Email:"
|
||||
@@ -2091,7 +2091,7 @@ msgstr "Mot de passe:"
|
||||
#: ~/Themes/Corporate/Views/LogOn.ascx
|
||||
#| msgid : "Remember me?"
|
||||
msgid "Remember me?"
|
||||
msgstr "Souviens-moi?"
|
||||
msgstr "Se souvenir de moi?"
|
||||
|
||||
#: ~/Themes/Corporate/Views/User.ascx
|
||||
#| msgid : "Log Off"
|
||||
|
128
src/Orchard.Web/Modules/Orchard.Blogs/Commands/BlogCommands.cs
Normal file
128
src/Orchard.Web/Modules/Orchard.Blogs/Commands/BlogCommands.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Blogs.Models;
|
||||
using Orchard.Commands;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Navigation.Models;
|
||||
using Orchard.Security;
|
||||
using System.IO;
|
||||
using Orchard.Blogs.Services;
|
||||
using Orchard.Core.Navigation.Services;
|
||||
|
||||
namespace Orchard.Blogs.Commands {
|
||||
public class BlogCommands : DefaultOrchardCommandHandler {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IMembershipService _membershipService;
|
||||
private readonly IBlogService _blogService;
|
||||
private readonly IMenuService _menuService;
|
||||
|
||||
public BlogCommands(
|
||||
IContentManager contentManager,
|
||||
IMembershipService membershipService,
|
||||
IBlogService blogService,
|
||||
IMenuService menuService) {
|
||||
_contentManager = contentManager;
|
||||
_membershipService = membershipService;
|
||||
_blogService = blogService;
|
||||
_menuService = menuService;
|
||||
}
|
||||
|
||||
[OrchardSwitch]
|
||||
public string FeedUrl { get; set; }
|
||||
|
||||
[OrchardSwitch]
|
||||
public string Slug { get; set; }
|
||||
|
||||
[OrchardSwitch]
|
||||
public string Title { get; set; }
|
||||
|
||||
[OrchardSwitch]
|
||||
public string MenuText { get; set; }
|
||||
|
||||
[CommandName("blog create")]
|
||||
[CommandHelp("blog create /Slug:<slug> /Title:<title> [/MenuText:<menu text>]\r\n\t" + "Creates a new Blog")]
|
||||
[OrchardSwitches("Slug,Title,MenuText")]
|
||||
public string Create() {
|
||||
var admin = _membershipService.GetUser("admin");
|
||||
|
||||
if(!IsSlugValid(Slug)) {
|
||||
return "Invalid Slug provided. Blog creation failed.";
|
||||
}
|
||||
|
||||
var blog = _contentManager.New("blog");
|
||||
blog.As<ICommonAspect>().Owner = admin;
|
||||
blog.As<RoutableAspect>().Slug = Slug;
|
||||
blog.As<RoutableAspect>().Title = Title;
|
||||
if ( !String.IsNullOrWhiteSpace(MenuText) ) {
|
||||
blog.As<MenuPart>().OnMainMenu = true;
|
||||
blog.As<MenuPart>().MenuPosition = _menuService.Get().Select(menuPart => menuPart.MenuPosition).Max() + 1 + ".0";
|
||||
blog.As<MenuPart>().MenuText = MenuText;
|
||||
}
|
||||
_contentManager.Create(blog);
|
||||
|
||||
return "Blog created successfully";
|
||||
}
|
||||
|
||||
[CommandName("blog import")]
|
||||
[CommandHelp("blog import /Slug:<slug> /FeedUrl:<feed url>\r\n\t" + "Import all items from <feed url> into the blog at the specified <slug>")]
|
||||
[OrchardSwitches("FeedUrl,Slug")]
|
||||
public string Import() {
|
||||
var admin = _membershipService.GetUser("admin");
|
||||
|
||||
XDocument doc;
|
||||
|
||||
try {
|
||||
Context.Output.WriteLine("Loading feed...");
|
||||
doc = XDocument.Load(FeedUrl);
|
||||
Context.Output.WriteLine("Found {0} items", doc.Descendants("item").Count());
|
||||
}
|
||||
catch ( Exception ex ) {
|
||||
Context.Output.WriteLine(T("An error occured while loading the file: " + ex.Message));
|
||||
return "Import terminated.";
|
||||
}
|
||||
|
||||
var blog = _blogService.Get(Slug);
|
||||
|
||||
if ( blog == null ) {
|
||||
return "Blog not found at specified slug: " + Slug;
|
||||
}
|
||||
|
||||
foreach ( var item in doc.Descendants("item") ) {
|
||||
string postName = item.Element("title").Value;
|
||||
|
||||
Context.Output.WriteLine("Adding post: {0}...", postName.Substring(0, Math.Min(postName.Length, 40)));
|
||||
var post = _contentManager.New("blogpost");
|
||||
post.As<ICommonAspect>().Owner = admin;
|
||||
post.As<ICommonAspect>().Container = blog;
|
||||
post.As<RoutableAspect>().Slug = Slugify(postName);
|
||||
post.As<RoutableAspect>().Title = postName;
|
||||
post.As<BodyAspect>().Text = item.Element("description").Value;
|
||||
_contentManager.Create(post);
|
||||
}
|
||||
|
||||
|
||||
return "Import feed completed.";
|
||||
}
|
||||
|
||||
private static string Slugify(string slug) {
|
||||
var dissallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s]+");
|
||||
|
||||
slug = dissallowed.Replace(slug, "-");
|
||||
slug = slug.Trim('-');
|
||||
|
||||
if ( slug.Length > 1000 )
|
||||
slug = slug.Substring(0, 1000);
|
||||
|
||||
return slug.ToLowerInvariant();
|
||||
}
|
||||
|
||||
private static bool IsSlugValid(string slug) {
|
||||
// see http://tools.ietf.org/html/rfc3987 for prohibited chars
|
||||
return slug == null || String.IsNullOrEmpty(slug.Trim()) || Regex.IsMatch(slug, @"^[^/:?#\[\]@!$&'()*+,;=\s]+$");
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,6 +9,7 @@ namespace Orchard.Blogs.Models {
|
||||
|
||||
public string Name {
|
||||
get { return this.As<RoutableAspect>().Title; }
|
||||
set { this.As<RoutableAspect>().Title = value; }
|
||||
}
|
||||
|
||||
//TODO: (erikpo) Need a data type for slug
|
||||
|
@@ -66,6 +66,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Commands\BlogCommands.cs" />
|
||||
<Compile Include="Controllers\BlogAdminController.cs" />
|
||||
<Compile Include="Drivers\BlogDriver.cs" />
|
||||
<Compile Include="Controllers\BlogPostAdminController.cs" />
|
||||
|
@@ -15,7 +15,7 @@ namespace Orchard.Search.Controllers {
|
||||
}
|
||||
|
||||
public ActionResult Index(string q) {
|
||||
var searchViewModel = new SearchViewModel {Term = q};
|
||||
var searchViewModel = new SearchViewModel {Query = q};
|
||||
|
||||
var results = _searchService.Query(q);
|
||||
searchViewModel.Results = results.Select(result => new SearchResultViewModel {
|
||||
|
@@ -67,6 +67,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Controllers\SearchController.cs" />
|
||||
<Compile Include="Filters\SearchFilter.cs" />
|
||||
<Compile Include="Routes.cs" />
|
||||
<Compile Include="Services\ISearchService.cs" />
|
||||
<Compile Include="Services\SearchService.cs" />
|
||||
<Compile Include="ViewModels\SearchResultViewModel.cs" />
|
||||
|
34
src/Orchard.Web/Modules/Orchard.Search/Routes.cs
Normal file
34
src/Orchard.Web/Modules/Orchard.Search/Routes.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Orchard.Mvc.Routes;
|
||||
|
||||
namespace Orchard.Search {
|
||||
public class Routes : IRouteProvider {
|
||||
|
||||
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
||||
foreach (var routeDescriptor in GetRoutes())
|
||||
routes.Add(routeDescriptor);
|
||||
}
|
||||
|
||||
public IEnumerable<RouteDescriptor> GetRoutes() {
|
||||
return new[] {
|
||||
new RouteDescriptor {
|
||||
Priority = 5,
|
||||
Route = new Route(
|
||||
"Search",
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Search"},
|
||||
{"controller", "search"},
|
||||
{"action", "index"}
|
||||
},
|
||||
null,
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Search"}
|
||||
},
|
||||
new MvcRouteHandler())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Indexing;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
|
||||
namespace Orchard.Search.ViewModels {
|
||||
public class SearchViewModel : BaseViewModel {
|
||||
public IEnumerable<SearchResultViewModel> Results { get; set; }
|
||||
public string Term { get; set; }
|
||||
public string Query { get; set; }
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@ Html.RegisterStyle("search.css"); %>
|
||||
<%
|
||||
Html.Zone("search"); %><%
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Model.Term)) { %>
|
||||
if (!string.IsNullOrWhiteSpace(Model.Query)) { %>
|
||||
<p class="search-summary"><%=T("<em>{0}</em> results", Model.Results.Count()) %></p><%
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<%@ Import Namespace="Orchard.Search.ViewModels" %><%
|
||||
using(Html.BeginForm("index", "search", new { area = "Orchard.Search" }, FormMethod.Get, new { @class = "search" })) { %>
|
||||
<fieldset>
|
||||
<%=Html.TextBox("q", Model.Term) %>
|
||||
<%=Html.TextBox("q", Model.Query) %>
|
||||
<button type="submit"><%=T("Search") %></button>
|
||||
</fieldset><%
|
||||
} %>
|
@@ -336,6 +336,20 @@ namespace Orchard.ContentManagement {
|
||||
foreach (var handler in Handlers) {
|
||||
handler.Created(context);
|
||||
}
|
||||
|
||||
if(options.IsPublished) {
|
||||
var publishContext = new PublishContentContext(contentItem, null);
|
||||
|
||||
// invoke handlers to acquire state, or at least establish lazy loading callbacks
|
||||
foreach ( var handler in Handlers ) {
|
||||
handler.Publishing(publishContext);
|
||||
}
|
||||
|
||||
// invoke handlers to acquire state, or at least establish lazy loading callbacks
|
||||
foreach ( var handler in Handlers ) {
|
||||
handler.Published(publishContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ContentItemMetadata GetItemMetadata(IContent content) {
|
||||
|
@@ -43,6 +43,7 @@ namespace Orchard.FileSystems.WebSite {
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string virtualPath) {
|
||||
// Fix this to monitor first existing parent directory.
|
||||
var token = BindToken(virtualPath);
|
||||
BindSignal(virtualPath);
|
||||
return token;
|
||||
|
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using Orchard.Data;
|
||||
using Orchard.Localization.Records;
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
@@ -11,8 +12,8 @@ namespace Orchard.Localization.Services {
|
||||
private readonly IWebSiteFolder _webSiteFolder;
|
||||
private readonly ICultureManager _cultureManager;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly ICacheManager _cacheManager;
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly IList<CultureDictionary> _cultures;
|
||||
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 RootLocalizationFilePathFormat = "/App_Data/Localization/{0}/orchard.root.po";
|
||||
@@ -21,21 +22,26 @@ namespace Orchard.Localization.Services {
|
||||
public DefaultResourceManager(
|
||||
ICultureManager cultureManager,
|
||||
IWebSiteFolder webSiteFolder,
|
||||
IExtensionManager extensionManager,
|
||||
IExtensionManager extensionManager,
|
||||
ICacheManager cacheManager,
|
||||
ShellSettings shellSettings) {
|
||||
_cultureManager = cultureManager;
|
||||
_webSiteFolder = webSiteFolder;
|
||||
_extensionManager = extensionManager;
|
||||
_cacheManager = cacheManager;
|
||||
_shellSettings = shellSettings;
|
||||
_cultures = new List<CultureDictionary>();
|
||||
}
|
||||
|
||||
// This will translate a string into a string in the target cultureName.
|
||||
// The scope portion is optional, it amounts to the location of the file containing
|
||||
// the string in case it lives in a view, or the namespace name if the string lives in a binary.
|
||||
// If the culture doesn't have a translation for the string, it will fallback to the
|
||||
// parent culture as defined in the .net culture hierarchy. e.g. fr-FR will fallback to fr.
|
||||
// In case it's not found anywhere, the text is returned as is.
|
||||
public string GetLocalizedString(string scope, string text, string cultureName) {
|
||||
if (_cultures.Count == 0) {
|
||||
LoadCultures();
|
||||
}
|
||||
var cultures = LoadCultures();
|
||||
|
||||
foreach (var culture in _cultures) {
|
||||
foreach (var culture in cultures) {
|
||||
if (String.Equals(cultureName, culture.CultureName, StringComparison.OrdinalIgnoreCase)) {
|
||||
string scopedKey = scope + "|" + text;
|
||||
string genericKey = "|" + text;
|
||||
@@ -46,21 +52,21 @@ namespace Orchard.Localization.Services {
|
||||
return culture.Translations[genericKey];
|
||||
}
|
||||
|
||||
return GetParentTranslation(scope, text, cultureName);
|
||||
return GetParentTranslation(scope, text, cultureName, cultures);
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
private string GetParentTranslation(string scope, string text, string cultureName) {
|
||||
private static string GetParentTranslation(string scope, string text, string cultureName, IEnumerable<CultureDictionary> cultures) {
|
||||
string scopedKey = scope + "|" + text;
|
||||
string genericKey = "|" + text;
|
||||
try {
|
||||
CultureInfo cultureInfo = CultureInfo.GetCultureInfo(cultureName);
|
||||
CultureInfo parentCultureInfo = cultureInfo.Parent;
|
||||
if (parentCultureInfo.IsNeutralCulture) {
|
||||
foreach (var culture in _cultures) {
|
||||
foreach (var culture in cultures) {
|
||||
if (String.Equals(parentCultureInfo.Name, culture.CultureName, StringComparison.OrdinalIgnoreCase)) {
|
||||
if (culture.Translations.ContainsKey(scopedKey)) {
|
||||
return culture.Translations[scopedKey];
|
||||
@@ -78,21 +84,40 @@ namespace Orchard.Localization.Services {
|
||||
return text;
|
||||
}
|
||||
|
||||
private void LoadCultures() {
|
||||
foreach (var culture in _cultureManager.ListCultures()) {
|
||||
_cultures.Add(new CultureDictionary {
|
||||
CultureName = culture,
|
||||
Translations = LoadTranslationsForCulture(culture)
|
||||
});
|
||||
}
|
||||
// Loads the culture dictionaries in memory and caches them.
|
||||
// Cache entry will be invalidated any time the directories hosting
|
||||
// the .po files are modified.
|
||||
private IEnumerable<CultureDictionary> LoadCultures() {
|
||||
return _cacheManager.Get("cultures", ctx => {
|
||||
var cultures = new List<CultureDictionary>();
|
||||
foreach (var culture in _cultureManager.ListCultures()) {
|
||||
cultures.Add(new CultureDictionary {
|
||||
CultureName = culture,
|
||||
Translations = LoadTranslationsForCulture(culture, ctx)
|
||||
});
|
||||
}
|
||||
return cultures;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private IDictionary<string, string> LoadTranslationsForCulture(string culture) {
|
||||
// Merging occurs from multiple locations:
|
||||
// In reverse priority order:
|
||||
// "/Core/App_Data/Localization/<culture_name>/orchard.core.po";
|
||||
// "/Modules/<module_name>/App_Data/Localization/<culture_name>/orchard.module.po";
|
||||
// "/App_Data/Localization/<culture_name>/orchard.root.po";
|
||||
// "/App_Data/Sites/<tenant_name>/Localization/<culture_name>/orchard.po";
|
||||
// The dictionary entries from po files that live in higher priority locations will
|
||||
// override the ones from lower priority locations during loading of dictionaries.
|
||||
|
||||
// TODO: Add culture name in the po file name to facilitate usage.
|
||||
private IDictionary<string, string> LoadTranslationsForCulture(string culture, AcquireContext<string> context) {
|
||||
IDictionary<string, string> translations = new Dictionary<string, string>();
|
||||
string corePath = string.Format(CoreLocalizationFilePathFormat, culture);
|
||||
string text = _webSiteFolder.ReadFile(corePath);
|
||||
if (text != null) {
|
||||
ParseLocalizationStream(text, translations, false);
|
||||
context.Monitor(_webSiteFolder.WhenPathChanges(corePath));
|
||||
}
|
||||
|
||||
foreach (var module in _extensionManager.AvailableExtensions()) {
|
||||
@@ -101,6 +126,7 @@ namespace Orchard.Localization.Services {
|
||||
text = _webSiteFolder.ReadFile(modulePath);
|
||||
if (text != null) {
|
||||
ParseLocalizationStream(text, translations, true);
|
||||
context.Monitor(_webSiteFolder.WhenPathChanges(modulePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,12 +135,14 @@ namespace Orchard.Localization.Services {
|
||||
text = _webSiteFolder.ReadFile(rootPath);
|
||||
if (text != null) {
|
||||
ParseLocalizationStream(text, translations, true);
|
||||
context.Monitor(_webSiteFolder.WhenPathChanges(rootPath));
|
||||
}
|
||||
|
||||
string tenantPath = string.Format(TenantLocalizationFilePathFormat, _shellSettings.Name, culture);
|
||||
text = _webSiteFolder.ReadFile(tenantPath);
|
||||
if (text != null) {
|
||||
ParseLocalizationStream(text, translations, true);
|
||||
context.Monitor(_webSiteFolder.WhenPathChanges(tenantPath));
|
||||
}
|
||||
|
||||
return translations;
|
||||
|
Reference in New Issue
Block a user