turquoiseowl / i18n Goto Github PK
View Code? Open in Web Editor NEWSmart internationalization for ASP.NET
License: Other
Smart internationalization for ASP.NET
License: Other
Quite a small point this but perhaps a good time to mention it: some classes such as I18n, I18NWebViewPage etc. look to be interfaces rather than classes. It took me some time to get my head round this naming.
Any objections to renaming these? e.g. i18NWebViewPage
Hi. I've found a little issue - NUnit references in i18n.Tests project are pointing to GAC instead of local packages repository.
So me and Martin has been chatting and agreed that the way forward here as we see it is by manipulating the output (as previously discussed)
The plan goes that it's time to remove gettext and msgmerge. instead parsing all files according to white list and the having a proper domain model, that allows saving translation data either to po file like today or database (repository pattern).
So here is the list that we plotted down on things to do. Feel free to come with ideas about this.
https://docs.google.com/document/d/15A-bhM5-24Y6K0lMfl2dDSr1jscFIRadyVjnAId3Da0/edit?usp=sharing
Hi guys I migrated from v.1.0.8 to v2.0.. Everything Works fine on localhost server, but when I tried to publish App to Hostgator Windows Shared we get SecurityException because something in httpmodule use a unsupported trust level for shared hostings.
Dealing with xgettext location with PostBuild is a big impediment to library adoption and ease of use. Let's make this fully automatic.
Put this down as nice to have.
It would be great if the same tool that builds the POT file will also alert to static strings that are not localized.
This will be a common concern in larger products with several people will be involved in the development where it will be hard to enforce puting strings under localization
I put post event as instruction - "$(TargetDir)i18n.PostBuild.exe" "$(ProjectDir)"
The /locale/messages.po file get created, no content in it however.
I've been trying to work out how to localize DataAnnotations, jQuery.validation stuff etc. and had an idea:
Is there scope in i18n for general processing of the HTTP response output and making translation there. E.g. we could scan for msgids wrapped in some markers like ###Translate me!###, lookup any corresponding message and, if found, swap it in.
Maybe this has already been thought of, or is not practical?
About to go away and investigate ASP.NET HttpModules/Handlers... I guess it would also require xgettext or equivalent to be able to locate these marked strings in the project source.
Hi. If you didn't create 'locale' folder manually under the project root, you'll have DirectoryNotFoundException. It would be greate if this folder created automatically in cases when it wasn't found.
I can see 3 approaches for a site to URL handling and redirection so far (assuming the example.com/en pattern). Let us assume default app language is en. Then we could want:
Hi Daniel,
here is some initial feedback I collected:
LocalizingService
// Save cycles processing beyond the default; just return the original key
if (culture.TwoLetterISOLanguageName.Equals(I18N.DefaultTwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase))
{
return key;
}
imho that is not totally correct. In many cases the key used could be something like "Home.WelcomeParagraph", and not just "Hi, and welcome to my brand new home page", so it will fail for the default language. I modified it to return the regional content found.
gettext is a bit out of date, but I haven't been able to find an updated win32 version. In some cases it fails to export strings, eg: <img src="@href(_("myimg"))"/>
some parsing issues: this is probably related to POEdit, but I'm having some issues when translations become obsolete or are not confirmed (they throws null reference exceptions).
That's all for now :-)
Ciao,
Petrhaus.
I am doing a very simple jquery ajax call like this:
ajaxSearchCall = $.ajax({
type: "POST",
url: "@Url.Action("Search")",
data: "searchString=" + $("#searchString").val(),
dataType: "html"
});
So I use Url.Action to get my path and it gives me url: "/AdminRoot/Search",
Which is correct but does not contain language string in path.
What then happens can be seen here in this screenshot from chrome
http://db.tt/seJksqpy
It sends the post (with the post data). What it gets back is a 302 (Moved temporarily) to the same path but with /en/ in front of it. So with language code.
But then as you can see chrome calls this path with GET not post any more, and it does not send in the post data again either.
I have not dugg into the code to see exactly where this happens, but it is i18n project because disabling i18n i web.config fixes the issue.
I think to fix this we need one of many solutions.
I am sure there are other solution as well but number one seems the easiest to me. We can still populate all the language data and run full i18n for the request. only that we don't redirect on post.
I am struggling with this. The only answer I can find is regarding v2 and setting a cookie there. How does it work for v1?
In the app I'm working on I need to retain context for each translatable message, for example although the text "hammer" may appear multiple times, in some languages it may have to be translated into different words depending on the context of the page (this is a contrived example, but I hope this is clear).
Gettext has the idea of the msgctxt which will allow the disambiguation of the otherwise identical words, and editors like poedit can handle this. I don't see any way to handle this inside i18n, is this proposed for V2?
Hi I was just cleaning up my nuget references and went to reinstall i18n and i got:
PM> Install-Package i18n
Attempting to resolve dependency 'CommonServiceLocator (≥ 1.0)'.
Successfully installed 'CommonServiceLocator 1.0'.
Successfully installed 'I18N 1.0.5'.
Successfully added 'CommonServiceLocator 1.0' to SelogerCity.Web.
Successfully uninstalled 'I18N 1.0.5'.
Successfully uninstalled 'CommonServiceLocator 1.0'.
Install failed. Rolling back...
Install-Package : Failed to add reference to 'envsubst'.
At line:1 char:16
I'm running NuGet 1.62.21215.9133
Not sure if anyone has mentioned this yet, but '_' is the line continuation character in VB.Net. I've been using my own compiled version of the source and changing the function name to '__', but I would say this is definitely an issue.
Hey.
In our project we need a few translation "packages" so the structure in output folder would be like:
OutputFolder
etc.
So we need more configurable solution than the one in PostBuild in v2.0 is.
Check this out:
https://github.com/ciscoheat/i18n/blob/master/src/i18n.PostBuild/app.config
This PostBuild is more configurable than yours. You should really consider using this solution - it is easier to use app.config and pass parameters there than putting parameters in post build action (i.e. I couldn't pass output folder path that has spaces).
I've started implementing some solution myself, but than i found yours. Now i'm thinking is it possible to make it happen using your framework.
Lets say that i want to have two totally different URLs for different languages, for instance:
for 'en': /en/lessons/
for 'he': /he/שיעורים/
Both of the URLs must be routed to the same controller and action.
In plain MVC Routing it'll look something like this:
routes.MapRoute("en_Lessons_List", "en/Lessons/", new { controller = "Lessons", action = "List", culture = "en" });
routes.MapRoute("he_Lessons_List", "he/שיעורים/", new { controller = "Lessons", action = "List", culture = "he" });
Is this approach possible under your framework?
I have a use case where the user can select the language they want to view the page in. How do I set the language based on Query string?
Using Automatic route localization under a virtual application directory does not work. The language is prepended to before the application directory.
Eg www.somesite.com/Application1 - virtual application directory
Redirect goes to www.somesite.com/en/Application1
It needs to go to www.somesite.com/Application1/en
Even typing in the correct url does not pull up the correct page.
This scenario should be supported and should return with default language in case of missing "Accept-Language" in http request header
I'm updatnig the readme and it mentions ILocalizing a lot but can't work out what this is for. It is implemented liberally but not actually queried-for or called-through anywhere.
Furthermore, it only has the one method:
_();
and doesn't include the newer and overloaded one:
__();
Do we need it?
Sometimes we need a tool generate or migrate strings(unicode(e.g. Chinese words, Japanese words)) to pot file.
Webapi methods should also be able to return results in the requested language, including error descriptions
Right now, nugget tokens are ignored and returned as is, so for example you will see the action returning a "[[[Success]]]" tag if your method was supposed to return an internationalized version of the string.
Before it was possible to implement the localized interfase in the controller and use that to internationalize the strings.
When I add the call to I18N.Register() in the global.asax Application_Start() method after routes have been registered I get a resource not found exception. Looks like MVC is trying to redirect to the virtual directory /en-us
Is there any other requirement needed that is not specified in the readme file of this project to enable automatic localized routing?
Thanks a lot
What needs to be setup in Application_Start() in V2.0?
There are sample projects prior Prior to V2.0 where i18n.Register() is called in Application_Start(), but that is not available any more. So how to you configure it now? There should be ideally a smaple project for V2.0 as well.
At the moment we have the following call which enables localization of routes:
i18n.I18N.Register();
I propose we move the route localization stuff out of the I18N class into one called RouteLocalization, and replace the above call with:
i18n.RouteLocalization.Enable();
The RouteLocalization class will then become the focus for configuration and extensibility of this feature e.g. a IRouteLocalizer service and handling scheme (issue #31).
Works fine on IIS and IIS Express but for some reason in Cassini the translations are not happening which makes me think the module is not being loaded. I'll try to run more experiments later and see exactly what is happening but an initial internet search didn't turn up any reasons why Cassini might choose to ignore a module defined in the web.config
In answer to @rickardliljeberg's question, this is how you can set the user's preferred language in your controller (using v2.0 branch of i18n):
//
// GET: /Account/SetLanguage
[AllowAnonymous]
public ActionResult SetLanguage(string langtag, string returnUrl)
{
DebugHelpers.WriteLine("AccountController::SetLanguage -- GET -- langtag: {0}, returnUrl:{1}",
langtag,
returnUrl);
// If valid 'langtag' passed.
i18n.LanguageTag lt = i18n.LanguageTag.GetCachedInstance(langtag);
if (lt.IsValid()) {
// Set persistent cookie in the client to remember the language choice.
Response.Cookies.Add(new HttpCookie("i18n.langtag")
{
Value = lt.ToString(),
HttpOnly = true,
Expires = DateTime.UtcNow.AddYears(1)
});
}
// Owise...delete any 'language' cookie in the client.
else {
Response.Cookies["i18n.langtag"].FlagForRemoval(); }
// Patch in the new langtag into any return URL.
if (returnUrl.IsSet()) {
returnUrl = i18n.LanguageTag.SetLangTagInUrlPath(returnUrl, UriKind.RelativeOrAbsolute, lt == null ? null : lt.ToString()).ToString(); }
// Redirect user agent as approp.
return this.Redirect(returnUrl);
}
I try to open v2.0 solution in VS2012 and I get this error:
Unsupported
This version of Visual Studio does not have the following project types installed or does not support them. You can still open these projects in the version of Visual Studio in which they were originally created.
- i18n.POTGenerator, "(mu user path)\Desktop\i18n-2.0\src\i18n.POTGenerator\i18n.POTGenerator.csproj"
No changes required
These projects can be opened in this version of Visual Studio without changing them. They will continue to open in Visual Studio 2010 SP1 and in this version of Visual Studio.
- i18n, "(my user path)\Desktop\i18n-2.0\src\i18n\i18n.csproj"
- Solution Items, "Solution Items"
- i18n.PostBuild, "(my user path)\Desktop\i18n-2.0\src\i18n.PostBuild\i18n.PostBuild.csproj"
- i18n.Tests, "(my user path)\Desktop\i18n-2.0\src\i18n.Tests\i18n.Tests.csproj"
- i18n.Domain, "(my user path)\Desktop\i18n-2.0\src\i18n.Domain\i18n.Domain.csproj"
- i18n.Domain.Tests, "(my user path)\Desktop\i18n-2.0\src\i18n.Domain.Tests\i18n.Domain.Tests.csproj"
- i18n, "(my user path)\Desktop\i18n-2.0\src\i18n.sln"
When I debug code, I see error ocurred on this block:
url = url.Substring(0, url.Length -suffix.Length);
var originalRequest = new ClonedHttpRequest(context.Request, url);
var originalContext = new ClonedHttpContext(context, originalRequest);
result = _route.GetRouteData(originalContext);
if (result != null)
{
// Found the original non-decorated route
return result;
}
result = route.GetRouteData(originalContext) always return null; seems like originalcontext never get route values (and language route value).
My site is running ASP.NET MVC 4, with Entity Framework using IIS Express with Visual Studio 2012
This is error details:
Source code error:
Línea 30: public override string AppRelativeCurrentExecutionFilePath
Línea 31: {
Línea 32: get { return VirtualPathUtility.ToAppRelative(_url); }
Línea 33: }
Línea 34: public override string CurrentExecutionFilePath
Stack Trace:
[ArgumentNullException: Value cannot be null.
Parameter name: virtualPath]
System.Web.VirtualPath.Create(String virtualPath, VirtualPathOptions options) +9800033
System.Web.VirtualPathUtility.ToAppRelative(String virtualPath) +13
i18n.ClonedHttpRequest.get_AppRelativeCurrentExecutionFilePath() in c:\Users\Kellerman\Documents\GitHub\i18n\src\i18n\ClonedHttpRequest.cs:32
System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext) +49
i18n.LanguageRouteDecorator.GetRouteData(HttpContextBase context) in c:\Users\Kellerman\Documents\GitHub\i18n\src\i18n.MVC3\LanguageRouteDecorator.cs:42
System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext) +233
System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +60
System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +82
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
Hey,
is v2.0 stable? If not, when would it be?
Hello, i8ln isn't picking up strings that are inside script thats on cshtml pages.
For example:
<script> showAlert("@_("Unable to submit comments at this time")"); </script>Doesn't get added to the pot file.
A very typical scenario involves putting the model or some other shared classes (like a base controller) in a shared library that then multiple applications can use.
In that scenario there are 2 things that would be desirable:
I'm thinking of extending __() method adding the following method
public string __(string text, params object[] parameters)
{
return String.Format(_session.GetText(Context, text), parameters);
}
This method will help me to translate strings like __("Hello {0}!", "juan") or __("you've earned {0} point of {1}", 1, 10)
In spanish I want to get: "{0} bienvenido nuevamente" or "ganaste 1 punto de un total de 10"
What do you think about this?
I propose that the I18NSession class is in fact redundant.It has some virtual methods suggesting it was intended at some point to be extendable, yet instantiation of it is hard coded.
Any functionality can be better refactored to be extension methods of HttpContext/Base.
For extensibility we then focus on the LocalizingService interface and class.
Raising this as an issue in case I'm missing something?
Hi,
nuget package does not install correctly, this is the error message I get:
Install failed. Rolling back...
Install-Package : Failed to add reference to 'envsubst'.
At line:1 char:16
Any idea why this happens?
Sorry, but I can't make it work... whenever I add a "msgmerge:-N" parameter to PostBuild.exe, even using directly from command line, it allways gives me the same error, which I paste:
This is the command I run:
C:\Users\javizcaino>"C:\Documents\Projects\MVC4Bootstrap\MVC4Bootstrap\bin\i18n.PostBuild.exe" "C:\Documents\Projects\MVC4Bootstrap\MVC4Bootstrap\" "msgmerge:-N"
And this is the exception thrown:
Unhandled Exception: System.ArgumentException: Illegal characters in path. at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional) at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength) at System.IO.Path.GetFullPathInternal(String path) at System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost) at System.IO.Directory.GetFiles(String path, String searchPattern, SearchOption searchOption) at i18n.PostBuildTask.BuildProjectFileManifest(String path) in c:\Users\Daniel\Desktop\Src\i18n\src\i18n\PostBuildTask.cs:line 84 at i18n.PostBuildTask.Execute(String path, String gettext, String msgmerge) in c:\Users\Daniel\Desktop\Src\i18n\src\i18n\PostBuildTask.cs:line 22 at i18n.PostBuild.Program.Main(String[] args) in c:\Users\Daniel\Desktop\Src\i18n\src\i18n.PostBuild\Program.cs:line 30
This happens with every project I have tried.
If I remove the "msgmerge-N" it all runs flawless
What I'm doing wrong?
Have to admit that I am very new to unit testing but the only 2 tests in the project both fail for me. Are the supposed to succeed?
They are being taken into account for parsing and building the POT files, but for localizing the pages, no joy (it's actually hard coded that they be the default ones)
Same thing for black and white list
Hello,
Is it possible to have localized routes? For example:
/en-US/post/show/1/hello-world
/en-GB/post/show/1/hello-world
/pt-PT/artigo/ver/1/ola-mundo
The culture code is optional but useful to distinguish between en-US and en-GB when necessary.
Thank You,
Miguel
Once a language is selected (either by user interaction or automatic selection process) stick to it and rather display msgid than other languages.
cases for when current behavior is nice
a1. User like me speaks both swedish and english (selects english but can still see missing translations in swedish)
a2. User knows what he is doing and has set his browser language tags perfectly
cases where the other version is better
b1. Users who do not know or have energy to set browser languages
b2. Users who for any reason is on computer that returns language he does not speak (borrowed or his own)
b3. It can look bad with mixed languages on site (even if user speaks all)
Using the following configuration:
i18n.LocalizedApplication.Current.ContentTypesToLocalize = new Regex("^(?:text/html)$");
i18n.LocalizedApplication.Current.DefaultLanguage = "en";
i18n.LocalizedApplication.Current.PermanentRedirects = true;
i18n.LocalizedApplication.Current.EarlyUrlLocalizerService = null;
i18n.UrlLocalizer.UrlLocalizationScheme = i18n.UrlLocalizationScheme.Scheme2;
i18n.UrlLocalizer.IncomingUrlFilters += delegate(Uri url)
{
if (url.LocalPath.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
return false;
if(url.LocalPath.EndsWith(".css", StringComparison.InvariantCultureIgnoreCase))
return false;
if (url.LocalPath.EndsWith(".js", StringComparison.InvariantCultureIgnoreCase))
return false;
return true;
};
When attempting to handle a request that has no accept-language header, the language item will through an unhandled exception. This causes a problem since web crawlers and some smartphone browsers don't have this tag.
Expected behavior: It should default to the application's default language and respond to these requests appropiately.
The default nuggets "[[[" and "]]]" are a somewhat common combination when building a json structure that has arrays within arrays.
Since most people will not change the default, we should try to make sure we pick one that is failry unique among the domains we are targeting (C#, Razor, HTML, Json, Css, XML and all other web-related techs for .net based websites)
I've opened this issue so we can track suggestions as well
I've been experimenting with '[||[' and ']||]', and they seem to work pretty well as '||' is generally used as an or operator that is binary which will make it fail because of the brackets so it is very unlikely we'll run into a case where this has a valid meaning in one of the targeted domains.
Maybe I'm misunderstanding something but I would expect the strings put inside the Display attribute (for example) to be included in the POT file when it is built.
I understand the attribute will make the string pass through the localization filter but it is forcing people now to manually add these entries into the POT file and hence making it a lot harder to use for people.
When using a virtual folder configuration and the default early url localizer, for example 'localhost/MyApp/' there is a problem when trying to access the root. The error seems to indicate it's trying to find 'MyApp' as a controller when it should acknowledge that from the routing table that parameter is implicit for the default route.
No doubt we have all come to this i18n project looking for a better way to internationalize our web applications. We see that doing the old .NET resource look-up is backward. I expect we also see that leveraging the PO infrastructure for getting messages translated is the way forward.
Unfortunately, the PO infrastructure (i.e. the GNU Portable Object file format specification and the world of tools for translating the files) is very much tethered to GetText, the latter being very backward IMO.
Whoever invented GetText had a brain-wave: we can encode strings in our source code in such a way that A) they can be hooked at run-time, and B) we can find and extract those strings from the source code. A very nice duality! So he or she wrote a library of functions that can look-up and swap message strings, and a tool for scanning source code files for those function calls and extracting message strings to be translated. It therefore assumes that all your message strings are contained in source code files which it can parse, and that they can be encoded as an argument to a function call e.g. _("Translate me!");
For someone facing the problem of how to internationalize a GUI app written in C, GetText is a good approach. For a back-end server program (like a web application), I suggest it is also reasonable, but not the best. With a back-end application, we have access to the output stream, and with a web application it is very easy to get at the HTTP response and do our translations there.
Now, as soon as we drop one side of the duality, one might start to wonder about the other side.
The question is, why bother with all those _()
functions when we only need them to mark the message strings (given that we can hook into the HTTP response body). The reason, of course, is that we still need to mark the message strings so they can be extracted into the PO file. Okay, but if we were going to choose a method for marking message strings for extraction, unhindered by any considerations other than it needs to be reliable, would we choose prefixing the string with _("
and suffixing with ")
?
There must be a better way to mark message strings, so that they can be easily picked up in source code and the HTTP response. The same algorithm can be used for both. Better still would be compatibility with SQL LIKE so that they can be extracted from database tables too e.g. product descriptions.
The marking can be done in the string itself, so message strings can be written straight into source files without the need to call any helper functions. Very useful for const strings such as C# attributes and data annotations. They would be entirely language independent: C#, Razor, JavaScript, HTML. They can also be written straight into database fields. No need to think "how do I access that helper function?"
Performing the translations at the HTTP response layer has the advantage of confining message look-up and patching to a single place, hence efficiency gains. It reduces dependency on any particular web development platform; we can forget about MVC and drop down the stack to ASP.NET (or even lower).
So where are we with this? With Issue #37 I have taken a stab at defining a suitable message marking syntax, called the Nugget syntax. There will be scope for improvement on the syntax I have no doubt (and a better name). It would be great to have a discussion with you guys on this. I'm sure we can come up with a syntax that is easy to remember and use, and yet robust. Support for string formatting is essential (i.e. {0} substitution), and pluralization would be nice.
With the marking syntax defined, the only outstanding work is to swap out (or augment) the GetText-dependent post-build task with new logic for extracting the marked message strings and adding them to the PO output. My preference here would be to drop GetText altogether (along with the _() calls), but that would mean dropping backward compatibility for projects.
The v2.0 branch includes all the other support necessary for post-processing the HTTP response. At the moment it has support for processing the Nugget marking syntax, and changing that to support any new syntax would be trivial.
We then get to keep the best bits of the GNU translation project:
It has been a few months now that I have been developing a web app using i18n v2.0 branch, where there is the option to encode a message string as either _("Translate Me")
or "[[[Translate Me]]]"
. Given the latter takes no extra thought other than including the [[[
and ]]]
it wins every time.
Martin Connell
At present, it is possible for region-specific POs to be skipped by the language matching algorithm in LocalizingService.GetText.
For example, suppose the following:
Accept-Language: fr-CH, fr-CA
PO files: fr-CA, fr
What the client would expect here is that the fr-CA PO file would be used, and failing that the fr one.
However, what happens at the moment is fr-CH is matched first, and when that fails we immediately fall back to fr. Thus, fr-CA is never tried for which is a shame because it would have matched.
This can be solved by a two-phase language matching loop:
first iteration we only try for exact matches;
second iteration we allow for fall back from region-specific languages to region-neutral languages.
Code for this proposal to come shortly. Comment welcome on any implications of this, I can't think of any at present.
Does the default language need a sub-folder and a PO-file within the locale directory?
I have the following setup:
The following happens (I tracked this down via Visual Studio debugger):
GetText() loads the user languages correctly. But since the language de-de is not listed in the AcceptedLanguages collection (but en-us is) all texts are translated to English.
If I create a subfolder and a PO file for de-de, the problem is fixed, since now de-de is listed as accepted language.
Why is the library using an accepted language instead of the default language when the PAL (principal application language) is set to the default language?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.