What is the best way to support multiple languages for the interface in an ASP.NET MVC application? I've seen people use resource files for other applications. Is this still the best way?
If you're using the default view engines, then local resources work in the views. However, if you need to grab resource strings within a controller action, you can't get local resources, and have to use global resources.
This makes sense when you think about it because local resources are local to an aspx page and in the controller, you haven't even selected your view.
I found this resource to be very helpful
Its a wrapper round the HttpContext.Current.GetGlobalResourceString and HttpContext.Current.GetLocalResourceString that allows you to call the resources like this...
// default global resource
Html.Resource("GlobalResource, ResourceName")
// global resource with optional arguments for formatting
Html.Resource("GlobalResource, ResourceName", "foo", "bar")
// default local resource
Html.Resource("ResourceName")
// local resource with optional arguments for formatting
Html.Resource("ResourceName", "foo", "bar")
The only problem I found is that controllers don't have access to local resouce strings.
Yes resources are still the best way to support multiple languages in the .NET environment. Because they are easy to reference and even easier to add new languages.
Site.resx
Site.en.resx
Site.en-US.resx
Site.fr.resx
etc...
So you are right still use the resource files.
The Orchard project uses a shortcut method called "T" to do all in-page string translations. So you'll see tags with a #T("A String to Translate").
I intend to look at how this is implemented behind the scenes and potentially use it in future projects. The short name keeps the code cleaner since it will be used a lot.
What I like about this approach is the original string (english, in this case) is still easily visible in the code, and doesnt require a lookup in a resource tool or some other location to decode what the actual string should be here.
See http://orchardproject.net for more info.
Some of the other solutions mentioned as answer do not work for the released version of MVC (they worked with previous versions of alpha/beta).
Here is a good article describing a way to implement localization that will be strongly-typed and will not break the unit testing of controllers and views: localization guide for MVC v1
This is another option, and you'll have access to the CurrentUICulture in the controller:
Check MVC3-multi-language
Related
I am trying to add a few translations to the frontend of our module. When the translations are in the .tpl files they do get rendered. However no translation fields get shown in the backend my code for the .tpl files is:
{l s="Text" mod="myModule"}
I also do need to do some translating in the FrontControllers (mainly Error handling and feedback for serverside validation).
In the AdminController I simply use $this->l('Text'); which works. However, in the FrontController this is not available. I've checked the ControllerCore and FrontControllerCore, l() is not defined in those and only available in AdminController.
Can anyone give me a detailed explanation of what I need doing? All my research on the web always points to $this->l() being the thing to use...
When using translations in tpl files you need to use single quotes not double quotes.
{l s='Text' mod='myModule'}
As for front controllers... well if you're using custom module controllers as in controllers that extend ModuleFrontController you can use
$this->module->l('Text');
And if you're not using those controllers then... start using them.
Some things might be different since thirtybees is a fork of PrestaShop but I guess translation mechanism is the same.
I'm trying to use phpBB3 (forum app) along with ZF2. For that, I have to include a file from the phpBB3. In theory this is as simple as:
include('/path/to/phpbb3/common.php');
$user->session_begin(); //$user is defined in common.php file
In common.php a lot of globals are defined, and after that are required some files which are using those globals.
In ZF2 simply including the common.php would not work, because the scope of the globals will not span over the required files, so I tried a little trick:
//in Application/Forum/Service
public function callForumAPI(){
$zf_dir = getcwd();
chdir('/var/www/html/phpBB3');
include('common.php');
$user->session_begin();
chdir($zf_dir);
}
Neither in this case the scope of the global variables didn't span over the required files, so all the globals where NULL in those files.
How could I solve this issue?
I consider 2 main problems:
1. Loading resources
I dont know if you changed the code of phpBB3, since if you dont, your problem is other.
Phpbb3, as many systems, doesnt let you access directly to any file, you have to go through index.php. As you can see in common.php
if (!defined('IN_PHPBB'))
{
exit;
}
IN_PHPBB is defined in index.php, so you can simply use
Also, common.php and other files, makes use of $phpbb_root_path, that is defined in index.php.
So, at least, when you are going to include common.php you need
$zf_dir = getcwd();
chdir('/var/www/html/phpBB3');
define('IN_PHPBB', true);
$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
include('common.php');
...
chdir($zf_dir);
probably there are some other things you have to take care about.
2. Variable scopes
Also, consider than in PHP, like in almost every language, a variable declared inside a function, is considered local, and will be undefined outside that function. So for sure, if you do that inside callForumAPI(), you wont have any variable outside, and moreover, depending on where you are doing that includes...it could be actually inside a function, no matter you can notice it or not, since ZF2 is a framenwork with a complex, non-obvius architecture.
So, what i recomend, as soon as you load the file, is to use the ZF2 service manager to store all the variables and object than you would use in your application. This is a good measure even if you didnt need it,since this way you can have everything integrated as much as possible, it is important to minimize and localize access to phpbb3, since it is not meant to be a library, maintenance could be tricky, so if everyhing is in the same file, and then you create your own internal api through the service manager, it will more encapsulated and nicer. I assume you already know how to do this, if you dont, just let me know.
try this, and tell me if its enough or we need more research
Intro:
I'm trying out LESS in an asp.net mvc environment.
I use dotless for server side processing (and I wouldn't want to use client side processing especially afer publishing the complete project).
I have to apply a design where there are different color schemes depending on different things (e.g. time of the day).
Less felt very powerful in this case as designing a parameterized css and only changing like 10 variables at the beginning of the file for every theme was really uplifting.
Problem:
But I would need to somehow change the color themes from an outside parameter.
Ideas:
First I thought that an URL parameter like style.less?theme=fuschia would be good, but I found no way to parse something like this.
Then I thought that making a very short blue.less, green.less, orange.less consisting only declared color variables, and including the main.less in every one of them would be a solid solution.
I had no chance to try out the second solution, but I thought this would be a good time to ask for advice on the most robust way of doing this.
The problem again is: I want to control some things in my less file from the outside.
Yes you can (because I implemented that feature for exactly that reason).
Dotless supports parameters from the outside via the querystring parameter.
<link rel="stylesheet" href="style.less?foo=bar" />
Will let you use the following less:
#foo = bar;
The parameter injection code is very simple. it just prepends the variable declarations to your normal less file, so anything that comes as a querystring parameter will follow the above syntax.
The code in question is very simple: https://github.com/dotless/dotless/blob/master/src/dotless.Core/Engine/ParameterDecorator.cs
AFAIK, you cannot pass parameters for dotnetless to use to do the compile.
As a suggestion, why not just call different less files? This would be fairly easy to do by using a Viewbag property.
To make the different less ones, You first create a less file with each set of colors in them. Then you import your base css file. dotnetless will merge the color definations in the parent file with the usages in the base file. So you have something like -
#baseGray: #ddd;
#baseGrayDark: darken(#baseGray, 15%);
#baseGrayLight: lighten(#baseGray, 10%);
#import "baseCss.less";
I just tested this on and MVC3 project and it works.
Is there a lint utility for ASP.NET MVC? Given that I frequently specify views and links via strings, when I move things around or change entity names I often break things, which I then only find out about when something fails at runtime.
ReSharper's v6 (whose nightlies are now available, if you don't mind living on the edge) will catch this kind of error for you.
You can use Refactor -> Rename and enable Search in Strings to replace every string in the solution
Other option -- use the strongly typed helpers (which might still be in the futures assemblies). EG, Html.Action<ProductsController>(x => x.ShowProduct(id)) ; really the only way to fly.
I don't know that there's something like that, but I'll tell you what I do: All my view names are in a struct that contains string constants. It's a pain to keep it sync'ed as the project changes, but it's worth it because you're far more likely to catch errors if you're using
ViewNames.Customer
rather than
"customer"
Recently I created a spike of a view engine, in which views are plain classes, and the content is created by using funny using-scope blocks.
The code together with a simple sample site is available at http://code.google.com/p/sharp-view-engine/
Here I'd like to hear your opinions regarding such an idea. Is it completely weird or maybe someone likes it?
I would actually not like that.
I can agree with DSLs (such as a Parser-Combinator or for generating XML Nodes in a data-context), but in this case I think that too much is being put in code that. And, in the end, this just complicates boundaries and leads to hard-to-maintain code. (You can already do the same, but with more verbosity just using the "standard" Web Controls. You can always use {subblock} in C# to limit a variables scope.)
The approach I prefer to use is templates with bindings (but no "code in templates"). That makes it easy for the "designer" (hopefully not me, or the next person to come along and) edit the layout of the view how they see fit. However, the core logic (the available controls and bindings) are kept in the code -- uncluttered. (Another advantage with the templates is that if they externally housed they do not require a recompile for every little change.)
Simplicity and maintainability are like ... zen.
This is an interesting idea taken to the extreme I'd say. At my shop we're using html conventions for pretty much everything except our layout. The only real html we have in the project is our Spark master page. For generating the content itself we use a convention engine that that spits out a semantic html model. (We're using the HtmlTags library from FubuMVC to build the semantic model.)
An example convention for rendering a multiline text box looks like:
public static HtmlTag Build(ElementRequest req)
{
return Tags.TextArea
.Rows(6)
.Id(req.ElementId)
.Attr("name", req.ElementId)
.Text(req.StringValue());
}
These conventions get triggered from reflecting on the view model (or we can manually call them from a helper method). The output is rendered (via ToString()) into the content section of our master page. We're joking that pretty soon we won't even need a view engine.
ps here's how we handle nesting. (Your using blocks look cluttered!)
return Tags.Div.Nest(
Tags.Button("save").AddClass("positive"),
Tags.Span.Text(" or "),
Tags.Anchor.Text("cancel").AddClass("negative")
);
Nest() is an extension method that simply takes a params array of HtmlTag and appends them to the parent's children collection.