How to change locale in grails application and force the browser to use the same. I tried this solution.
def locale = new Locale("de","DE")
RequestContextUtils.getLocaleResolver(request).setLocale(request, response, locale)
Also tried to change browser location as well nothing worked.
Any suggestions?
You could make use of params.lang. I use a grails filter to set the language on every request, e.g.
languageFilter(controller: '*', action: '*')
{
before = {
params.lang = "de"
return true;
}
}
Related
I'd like to ignore hostname verify and ignore client side certification validation while calling https rest api with RestClient
I cannot find a way to do it without using builder.
and seems that the hostverifier does not work at all.
public interface RHPAMRestClient {
// Starts a new process instance of a specified process.
#POST
#Path("/server/containers/{containerId}/processes/{processId}/instances")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
Object startProcess(#PathParam String containerId, #PathParam String processId, Object req);
}
RHPAMRestClient c = RestClientBuilder.newBuilder()
.baseUri(new URI(""))
.sslContext(SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build())
.hostnameVerifier((hostname, session) -> {
System.err.println("hostname verifier");
return true;
})
.build(RHPAMRestClient.class);
c.startProcess("", "", null);
It seems that there is a missconfiguration in Quarkus.
According to the documents, https://quarkus.io/guides/native-and-ssl, ssl support should be enabled when using quarkus-rest-client and the property quarkus.ssl.native should be true.
But it seems that it is false, this causes the org.jboss.resteasy.microprofile.client.RestClientBuilderImpl to override your settings
if (!SSL_ENABLED) {
resteasyClientBuilder.httpEngine((new URLConnectionClientEngineBuilder()).resteasyClientBuilder(resteasyClientBuilder).build());
resteasyClientBuilder.sslContext((SSLContext)null);
resteasyClientBuilder.trustStore((KeyStore)null);
resteasyClientBuilder.keyStore((KeyStore)null, "");
}
Forcing the property to true will magically make everything work as expected.
So, just set
quarkus.ssl.native=true in your application.properties file
(using Quarkus 1.3.1.Final)
I'm working on adding localization to my web application. I have configured the IStringLocalizer and it is correctly reading string resources from two different resx files, depending on the browser setting. It then maps those string resources to ViewData, from which my View is getting text in correct language (not sure if that is the best approach, but for now I don't want to spent more time on this).
The thing is that I also have a drop down list in my UI, that allows users to manually switch language. I'm reading the value set by user in my controller action and adding it to cookies, but now I'd also like to set my applications' culture to the one matching the string in cookie.
Is it possible to set application culture from the controller action in MVC Core? If yes, then how to do this correctly?
EDIT:
I have just learned that I can do something like this:
<a class="nav-item nav-link" asp-route-culture="en-US">English</a>
and it will add ?culture=en-US to my route, which will set culture for the page for me. Is there any way to do the same without having to keep it in an address bar?
EDIT 2:
Regarding answer by Adam Simon:
CookieRequestCultureProvider is what I'd like to use in my app, but the problem is that it is not producing any cookie. Documentation says that .net core will resolve which provider to use by checking which will give a working solution, starting from QueryStringRequestCultureProvider, then going to CookieRequestCultureProvider, then other providers.
My current Startup looks like this:
public class Startup
{
private const string defaultCulutreName = "en-US";
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo(defaultCulutreName),
new CultureInfo("pl-PL")
};
options.DefaultRequestCulture = new RequestCulture(defaultCulutreName, defaultCulutreName);
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
//TRIED PLACING IT BEFORE AND AFTER UseRequestLocalization
//CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("pl-PL", "pl-PL"));
app.UseRequestLocalization(app.ApplicationServices
.GetService<IOptions<RequestLocalizationOptions>>().Value);
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("pl-PL", "pl-PL"));
app.UseMvc(ConfigureRoutes);
}
private void ConfigureRoutes(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("Default", "{controller=About}/{action=About}");
}
}
Regarding CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("pl-PL", "pl-PL")) I have tried putting it in RequestLocalizationOptions in ConfigureServices, in Configure before UseRequestLocalization and after that. All with the same result.
The following "problems" appear with this solution:
MakeCookieValue method is not producing any .AspNetCore.Culture cookie
Chrome browser with language set to PL is using pl-PL culture
correctly, yet Firefox is using en-US culture with language set to PL
in options (despite commenting out options.DefaultRequestCulture =
new RequestCulture(defaultCulutreName, defaultCulutreName) line)
Somehow my localization is working by default without using query
strings nor cookies to provide culture for application, but this is
not how I'd like it to work, as I do not have any control over it
Somehow you must tie the selected culture to the user so if you don't want to carry it around in the URL, you must find another way to retain this piece of information between requests. Your options:
cookie
session
database
HTTP header
hidden input
Under normal circumstances using a cookie to store the language preference is a perfect choice.
In ASP.NET Core the best place to retrieve and set the culture for the current request is a middleware. Luckily, the framework includes one, which can be placed in the request pipeline by calling app.UseRequestLocalization(...) in your Startup.Configure method. By default this middleware will try to pick up the current culture from the request URL, cookies and Accept-Language HTTP header, in this order.
So, to summarize: you need to utilize the request localization middleware, store the user's culture preference in a cookie formatted like c=%LANGCODE%|uic=%LANGCODE% (e.g. c=en-US|uic=en-US) and you are done.
You find all the details in this MSDN article.
Bonus:
It then maps those string resources to ViewData, from which my View is
getting text in correct language (not sure if that is the best
approach, but for now I don't want to spent more time on this).
Passing localized texts to views in ViewData is cumbersome and error-prone. In ASP.NET Core we have view localization for this purpose. You just need to inject the IViewLocalizer component into your views to get a nice and convenient way to access your localized text resources. (Under the hood IViewLocalizer uses IStringLocalizer.)
About EDIT 2
MakeCookieValue method is not producing any .AspNetCore.Culture cookie
CookieRequestCultureProvider.MakeCookieValue method is just a helper to generate a cookie value in the correct format. It just returns a string and that's all. But even if it were meant to add the cookie to the response, calling it in Startup.Configure would be completely wrong as you configure the request pipeline there. (It seems to me you're a bit confused about request handling and middlewares in ASP.NET Core so I suggest studying this topic.)
So the correct setup of the request pipeline is something like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
#region Localization
// REMARK: you may refactor this into a separate method as it's better to avoid long methods with regions
var supportedCultures = new[]
{
new CultureInfo(defaultCultureName),
new CultureInfo("pl-PL")
};
var localizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(defaultCultureName, defaultCultureName),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
// you can change the list of providers, if you don't want the default behavior
// e.g. the following line enables to pick up culture ONLY from cookies
RequestCultureProviders = new[] { new CookieRequestCultureProvider() }
};
app.UseRequestLocalization(localizationOptions);
#endregion
app.UseStaticFiles();
app.UseMvc(ConfigureRoutes);
}
(A remark on the above: it's unnecessary to register RequestLocalizationOptions in the DI container.)
Then you can have some controller action setting the culture cookie:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SetCulture(string culture, string returnUrl)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
// making cookie valid for the actual app root path (which is not necessarily "/" e.g. if we're behind a reverse proxy)
new CookieOptions { Path = Url.Content("~/") });
return Redirect(returnUrl);
}
Finally, an example how to invoke this from a view:
#using Microsoft.AspNetCore.Localization
#using Microsoft.AspNetCore.Http.Extensions
#{
var httpContext = ViewContext.HttpContext;
var currentCulture = httpContext.Features.Get<IRequestCultureFeature>().RequestCulture.UICulture;
var currentUrl = UriHelper.BuildRelative(httpContext.Request.PathBase, httpContext.Request.Path, httpContext.Request.QueryString);
}
<form asp-action="SetCulture" method="post">
Culture: <input type="text" name="culture" value="#currentCulture">
<input type="hidden" name="returnUrl" value="#currentUrl">
<input type="submit" value="Submit">
</form>
Chrome browser with language set to PL is using pl-PL culture correctly, yet Firefox is using en-US culture with language set to PL in options (despite commenting out options.DefaultRequestCulture =
new RequestCulture(defaultCulutreName, defaultCulutreName) line)
I suspect Chrome browser sends the language preference in the Accept-Language header while FF not.
Somehow my localization is working by default without using query strings nor cookies to provide culture for application, but this is not how I'd like it to work, as I do not have any control over it
I repeat:
By default this middleware will try to pick up the current culture from the request URL, cookies and Accept-Language HTTP header, in this order.
You can configure this behavior by changing or replacing the RequestLocalizationOptions.RequestCultureProviders list.
var constraintResolver = new DefaultInlineConstraintResolver()
{
ConstraintMap =
{
["apiVersion"] = typeof( ApiVersionRouteConstraint )
}
};
config.MapHttpAttributeRoutes(constraintResolver);
config.AddApiVersioning(o => o.AssumeDefaultVersionWhenUnspecified = true);
[ApiVersion("2.05")]
[RoutePrefix("api/v{version:apiVersion}/ger")]
public class caGerController
[Route("~/api/ger/getDetail")]
[Route("getDetail")]
GetGerData
[ApiVersion("1")]
[RoutePrefix("api/v{version:apiVersion}/gerDetail")]
public class caGerDetailsController
caGerController
[Route("~/api/gerDetail/getDetail")]
[Route("getDetail")]
GetGerData
>> GetGerData
Result:
Both URL working with v1 version ROUTE.
Second URL working for both, v1 and direct without v1 route as well i.e. [Route("~/api/gerDetail/getDetail")]
PROBLEM: first URL is only working with v1 and its not working with direct route like " [Route("~/api/ger/getDetail")]"
and getting an error as below:
"Error": {
"Code": "ApiVersionUnspecified",
"Message": "An API version is required, but was not specified."
}
How to solve this issue?
When I change from 2.05 to 1.0 then it works but 2.0 or 2.05 both do not work. Is there a separate folder required?
The ApiVersionUnspecified happens because all routes require an explicit API version by default. You opt out of this behavior using:
options.AssumeDefaultVersionWhenUnspecified = true
This setting means that a default API version is assumed when a client doesn't provide one. The default value is:
options.DefaultApiVersion // equals 1.0 by default
When you use the URL segment versioning method, you can't have two different controllers that both an unversioned route. The route without an API version can only map to a single controller. Since the default is "1.0" and you have a controller with the unversioned route, that's the one that will always been matched.
By adding API versioning, the default behavior is that it uses QueryString versioning.
config.AddApiVersioning(cfg => {});
api-version=1.0
To specify a version, you can add the querystring parameter api-version=1.0 at the end.
Example:
http://localhost:6600/api/test?api-version=1.0
You can change the version like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
...
public static void Register(HttpConfiguration config)
{
...
config.AddApiVersioning(cfg =>
{
cfg.DefaultApiVersion = new ApiVersion(1,1);
});
So you can change the version like this:
http://localhost:6600/api/test?api-version=1.1
By adding AssumeDefaultVersionWhenUnspecified, you don't have to specify a version.
config.AddApiVersioning(cfg =>
{
cfg.DefaultApiVersion = new ApiVersion(1,1);
cfg.AssumeDefaultVersionWhenUnspecified = true;
});
This will work:
http://localhost:6600/api/test
You can also add ReportApiVersions
config.AddApiVersioning(cfg =>
{
cfg.DefaultApiVersion = new ApiVersion(1,1);
cfg.AssumeDefaultVersionWhenUnspecified = true;
cfg.ReportApiVersions = true;
});
The response will have a new header api-supported-versions which specifies what versions are supported for the call they made.
I have a traditional Spring4/Thymeleaf i18n application
I switch the locale easily with classic
org.springframework.web.servlet.i18n.LocaleChangeInterceptor
and
org.springframework.web.servlet.i18n.CookieLocaleResolver
When switching I always send to the server /home?lang=fr. It works fine. But I need a more complex behaviour.
What I need to do is to preserve the current page while switching the locale.
I found a half-working solution with this thymeleaf snippet:
th:with="currentUrl=(${#httpServletRequest.pathInfo + '?' + #strings.defaultString(#httpServletRequest.queryString, '')})
The problem is I need to implement myself many corner cases:
when there is already any query parameter
if there is a lang=en param,
etc.
Does anybody know how to manage this case with native Spring or Thymeleaf tools? Or I need to write my own processor for Thymeleaf?
The easiest solution is concatenating "requestURI" and "queryString".
The drawback of this method is that if you click multiple times on the same link the parameter just gets added over and over again.
A workaround is to write a function that "cleans" the url before adding the parameter
For code examples, take a look at this question: Thymeleaf: add parameter to current url
I use this in my projects & it works fine. I don't specifically redirect to any URL when locale change.
#Bean
public LocaleResolver localeResolver()
{
Locale defaultLocale = new Locale( env.getProperty( Constants.DEFAULT_LOCALE ) );
CookieLocaleResolver clr = new CookieLocaleResolver();
clr.setDefaultLocale( defaultLocale );
return clr;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor()
{
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName( "lang" );
return lci;
}
I have a project going on, and now [admin section is almost done] (I know bit late) I am trying to implement i18n to the project.
I think everything works fine except when I enter http://localhost/my_project while my_project is working directory with CI installation in it, I am redirected to the following http://localhost/my_project/enhome (no trailing slash after en) any ideas?
Expecting result http://localhost/my_project/en/home, not just home controller but all controllers are behaving same.
.htaccess, base_url and index_page are set right (all works without the i18n).
routes.php are out of stock
$route['default_controller'] = "home";
$route['404_override'] = '';
// URI like '/en/about' -> use controller 'about'
$route['^(en|de|fr|nl)/(.+)$'] = "$2";
// '/en', '/de', '/fr' and '/nl' URIs -> use default controller
$route['^(en|de|fr|nl)$'] = $route['default_controller'];
edit
I am using "new" i18n from I guess ellislab. Sorry for wrong link (for 1.7 CI version).
So after some digging, I found the problem in core file, on the bottom of this posted script there is variable $new_url and it was echoing Redirect triggered to http://192.168.1.184/my_project/enhome without the "fix". I just added the / in there and it works prefectly I wonder what happend here and if this is OK fix or not.
function MY_Lang() {
parent::__construct();
global $CFG;
global $URI;
global $RTR;
$this->uri = $URI->uri_string();
$this->default_uri = $RTR->default_controller;
$uri_segment = $this->get_uri_lang($this->uri);
$this->lang_code = $uri_segment['lang'] ;
$url_ok = false;
if ((!empty($this->lang_code)) && (array_key_exists($this->lang_code, $this->languages)))
{
$language = $this->languages[$this->lang_code];
$CFG->set_item('language', $language);
$url_ok = true;
}
if ((!$url_ok) && (!$this->is_special($uri_segment['parts'][0]))) // special URI -> no redirect
{
// set default language
$CFG->set_item('language', $this->languages[$this->default_lang()]);
$uri = (!empty($this->uri)) ? $this->uri: $this->default_uri;
//OPB - modification to use i18n also without changing the .htaccess (without pretty url)
$index_url = empty($CFG->config['index_page']) ? '' : $CFG->config['index_page']."/";
$new_url = $CFG->config['base_url'].$index_url.$this->default_lang()."/".$uri;
echo "Redirect triggered to ".$new_url;
//header("Location: " . $new_url, TRUE, 302);
// exit;
}
}
this library is little old never been updated author since long time and it works for CI 1.7 but here is updated version compatible with CI 2.1.* same library but updated version working same way you can download from here
CodeIgniter 2.1 internationalization i18n