संसाधनों के साथ एक अलग परियोजना का उपयोग करें
मैं इसे बाहर के अनुभव से बता सकता हूं, जिसमें 12 24 परियोजनाओं के साथ एक वर्तमान समाधान है जिसमें एपीआई, एमवीसी, प्रोजेक्ट लाइब्रेरी (कोर फंक्शनालिटीज), डब्ल्यूपीएफ, यूडब्ल्यूपी और एक्समरीन शामिल हैं। यह इस लंबे पोस्ट को पढ़ने के लायक है क्योंकि मुझे लगता है कि यह ऐसा करने का सबसे अच्छा तरीका है। वी.एस. उपकरणों की सहायता से अनुवाद एजेंसियों को भेजे जाने या अन्य लोगों द्वारा समीक्षा करने के लिए आसानी से निर्यात योग्य और आयात योग्य है।
EDIT 02/2018: फिर भी मजबूत होता जा रहा है, इसे एक .NET मानक लाइब्रेरी में परिवर्तित करने से यह .NET फ्रेमवर्क और NET कोर में भी उपयोग करना संभव बनाता है। मैंने इसे JSON में बदलने के लिए एक अतिरिक्त अनुभाग जोड़ा ताकि उदाहरण के लिए कोणीय इसका उपयोग कर सके।
EDIT 2019: ज़मारिन के साथ आगे बढ़ते हुए, यह अभी भी सभी प्लेटफार्मों पर काम करता है। उदाहरण के लिए Xamarin.Forms रेसक्स फ़ाइलों का उपयोग करने की सलाह देता है। (मैंने Xamarin.Forms में अभी तक एक ऐप विकसित नहीं किया है, लेकिन प्रलेखन, जो कि सिर्फ आरंभ करने के लिए विस्तृत करने का तरीका है, इसे कवर करता है: Xamarin.Forms प्रलेखन )। जेन्सन में परिवर्तित करने की तरह ही हम इसे Xamarin.Android के लिए एक .xml फ़ाइल में भी बदल सकते हैं।
EDIT 2019 (2): WPF से UWP में अपग्रेड करते समय, मैंने पाया कि UWP में वे एक और फिलामेंट का उपयोग करना पसंद करते हैं .resw
, जो कंटेंट समान के संदर्भ में है लेकिन उपयोग अलग है। मुझे ऐसा करने का एक अलग तरीका मिला, जो मेरी राय में, बेहतर है तो डिफ़ॉल्ट समाधान ।
EDIT 2020: बड़े (modulair) परियोजनाओं के लिए कुछ सुझाव अपडेट किए गए जिनके लिए कई भाषा परियोजनाओं की आवश्यकता हो सकती है।
तो, यह करने के लिए मिलता है।
प्रो की
- लगभग हर जगह ज़ोरदार टाइप किया गया।
- WPF में आपको डील नहीं करनी है
ResourceDirectories
।
- जहाँ तक मैंने परीक्षण किया है, ASP.NET, कक्षा पुस्तकालयों, WPF, Xamarin, .NET Core, .NET मानक के लिए समर्थित है।
- किसी अतिरिक्त तृतीय-पक्ष लाइब्रेरी की आवश्यकता नहीं है।
- संस्कृति का समर्थन करता है: एन-यूएस -> एन।
- बैक-एंड ही नहीं, MAM के लिए WPF और Xamarin.Forms, .cshtml के लिए XAML में भी काम करता है।
- आसानी से बदलकर भाषा में हेरफेर करें
Thread.CurrentThread.CurrentCulture
- खोज इंजन विभिन्न भाषाओं में क्रॉल कर सकते हैं और उपयोगकर्ता भाषा-विशिष्ट यूआरएल भेज या बचा सकते हैं।
कोन के
- WPF XAML कभी-कभी छोटी गाड़ी है, नए जोड़े गए तार सीधे दिखाई नहीं देते हैं। पुनर्निर्माण अस्थायी फिक्स (vs2015) है।
- UWP XAML इंटेलीजेंस सुझाव नहीं दिखाता है और डिजाइन करते समय पाठ नहीं दिखाता है।
- मुझे बताओ।
सेट अप
अपने समाधान में भाषा परियोजना बनाएं, इसे MyProject.Language जैसा नाम दें । इसमें एक फ़ोल्डर जोड़ें जिसे संसाधन कहा जाता है, और उस फ़ोल्डर में, दो संसाधन फ़ाइलें (.resx) बनाएं। एक ने Resources.resx और दूसरे ने Resources.en.resx (या .en-GB.resx को विशिष्ट) कहा। मेरे कार्यान्वयन में, मेरे पास डिफ़ॉल्ट भाषा के रूप में एनएल (डच) भाषा है, इसलिए यह मेरी पहली फ़ाइल में जाती है, और अंग्रेजी मेरी दूसरी फ़ाइल में जाती है।
सेटअप इस तरह दिखना चाहिए:
Resources.resx के लिए गुण होना चाहिए:
सुनिश्चित करें कि कस्टम टूल नेमस्पेस आपके प्रोजेक्ट नेमस्पेस पर सेट है। इसका कारण यह है कि WPF में, आप Resources
XAML के अंदर संदर्भ नहीं दे सकते ।
और संसाधन फ़ाइल के अंदर, सार्वजनिक के लिए पहुँच संशोधक सेट करें:
यदि आपके पास इतना बड़ा आवेदन है (मान लीजिए कि विभिन्न मॉड्यूल हैं) तो आप ऊपर की तरह कई प्रोजेक्ट बनाने पर विचार कर सकते हैं। उस स्थिति में आप अपनी कुंजी और संसाधन वर्गों को विशेष मॉड्यूल के साथ उपसर्ग कर सकते हैं। विजुअल स्टूडियो के लिए एक ही अवलोकन में सभी फाइलों को संयोजित करने के लिए सबसे अच्छे भाषा संपादक का उपयोग करें ।
किसी अन्य प्रोजेक्ट में उपयोग कर रहा है
अपनी परियोजना का संदर्भ: संदर्भ पर राइट क्लिक करें -> संदर्भ जोड़ें -> विषय / समाधान।
किसी फ़ाइल में नाम स्थान का उपयोग करें: using MyProject.Language;
बैक-एंड में इसका उपयोग करें:
string someText = Resources.orderGeneralError;
यदि संसाधन नामक कुछ और है, तो बस पूरे नामस्थान में डाल दें।
MVC में उपयोग करना
MVC में आप हालांकि आप भाषा सेट करना पसंद कर सकते हैं, लेकिन मैंने यूआरएल के पैरामीटर का इस्तेमाल किया है, जिसे इस तरह सेटअप किया जा सकता है:
अन्य मानचित्रणों के नीचे मार्गकॉन्फ़िग.क्स
routes.MapRoute(
name: "Locolized",
url: "{lang}/{controller}/{action}/{id}",
constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },
defaults: new { controller = "shop", action = "index", id = UrlParameter.Optional }
);
FilterConfig.cs (, जोड़े जाने के लिए अगर ऐसा है, को जोड़ने की जरूरत हो सकती FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
करने Application_start()
में विधिGlobal.asax
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ErrorHandler.AiHandleErrorAttribute());
filters.Add(new LocalizationAttribute("nl-NL"), 0);
}
}
LocalizationAttribute
public class LocalizationAttribute : ActionFilterAttribute
{
private string _DefaultLanguage = "nl-NL";
private string[] allowedLanguages = { "nl", "en" };
public LocalizationAttribute(string defaultLanguage)
{
_DefaultLanguage = defaultLanguage;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string lang = (string) filterContext.RouteData.Values["lang"] ?? _DefaultLanguage;
LanguageHelper.SetLanguage(lang);
}
}
LanguageHelper सिर्फ संस्कृति जानकारी सेट करता है।
public static void SetLanguage(LanguageEnum language)
{
string lang = "";
switch (language)
{
case LanguageEnum.NL:
lang = "nl-NL";
break;
case LanguageEnum.EN:
lang = "en-GB";
break;
case LanguageEnum.DE:
lang = "de-DE";
break;
}
try
{
NumberFormatInfo numberInfo = CultureInfo.CreateSpecificCulture("nl-NL").NumberFormat;
CultureInfo info = new CultureInfo(lang);
info.NumberFormat = numberInfo;
info.DateTimeFormat.DateSeparator = "/";
info.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
Thread.CurrentThread.CurrentUICulture = info;
Thread.CurrentThread.CurrentCulture = info;
}
catch (Exception)
{
}
}
.Cshtml में उपयोग करें
@using MyProject.Language;
<h3>@Resources.w_home_header</h3>
या यदि आप usings को परिभाषित नहीं करना चाहते हैं, तो बस पूरे नामस्थान में भरें या आप नीचे दिए गए नामस्थान को /Views/web.config में परिभाषित कर सकते हैं:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
...
<add namespace="MyProject.Language" />
</namespaces>
</pages>
</system.web.webPages.razor>
यह mvc कार्यान्वयन स्रोत ट्यूटोरियल: बहुत बढ़िया ट्यूटोरियल ब्लॉग
मॉडल के लिए कक्षा पुस्तकालयों में उपयोग करना
बैक-एंड का उपयोग करना समान है, लेकिन विशेषताओं में उपयोग करने के लिए सिर्फ एक उदाहरण है
using MyProject.Language;
namespace MyProject.Core.Models
{
public class RegisterViewModel
{
[Required(ErrorMessageResourceName = "accountEmailRequired", ErrorMessageResourceType = typeof(Resources))]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
}
}
यदि आपके पास फेरबदल है तो यह स्वचालित रूप से जांच करेगा कि क्या दिए गए संसाधन का नाम मौजूद है। यदि आप टाइप सेफ्टी पसंद करते हैं तो आप एनम उत्पन्न करने के लिए T4 टेम्प्लेट का उपयोग कर सकते हैं
WPF में उपयोग करना।
Ofcourse अपने MyProject.Language नाम स्थान का संदर्भ जोड़ें , हम जानते हैं कि इसे बैक-एंड में कैसे उपयोग किया जाए।
XAML में, किसी विंडो या UserControl के हेडर के अंदर, एक नेमस्पेस रेफरेंस जोड़ें lang
जैसे कि:
<UserControl x:Class="Babywatcher.App.Windows.Views.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject.App.Windows.Views"
xmlns:lang="clr-namespace:MyProject.Language;assembly=MyProject.Language" <!--this one-->
mc:Ignorable="d"
d:DesignHeight="210" d:DesignWidth="300">
फिर, एक लेबल के अंदर:
<Label x:Name="lblHeader" Content="{x:Static lang:Resources.w_home_header}" TextBlock.FontSize="20" HorizontalAlignment="Center"/>
चूंकि यह दृढ़ता से टाइप किया गया है आप सुनिश्चित हैं कि संसाधन स्ट्रिंग मौजूद है। सेटअप के दौरान आपको कभी-कभी परियोजना को फिर से शुरू करने की आवश्यकता हो सकती है, WPF कभी-कभी नए नामस्थानों के साथ छोटी गाड़ी है।
WPF के लिए एक और बात, भाषा को अंदर सेट करें App.xaml.cs
। आप अपना स्वयं का कार्यान्वयन (स्थापना के दौरान चुनें) कर सकते हैं या सिस्टम को निर्णय लेने दे सकते हैं।
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SetLanguageDictionary();
}
private void SetLanguageDictionary()
{
switch (Thread.CurrentThread.CurrentCulture.ToString())
{
case "nl-NL":
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("nl-NL");
break;
case "en-GB":
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
break;
default:
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
break;
}
}
}
UWP में उपयोग करना
UWP में, Microsoft इस समाधान का उपयोग करता है , जिसका अर्थ है कि आपको नई संसाधन फ़ाइलें बनाने की आवश्यकता होगी। साथ ही आप पाठ का फिर से उपयोग नहीं कर सकते क्योंकि वे चाहते हैं कि आप x:Uid
अपने नियंत्रण को XAML में अपने संसाधनों की कुंजी में सेट करें। और अपने संसाधनों में आपको Example.Text
एक TextBlock
पाठ को भरने के लिए करना होगा । मुझे वह समाधान बिल्कुल पसंद नहीं आया क्योंकि मैं अपने संसाधन फ़ाइलों का फिर से उपयोग करना चाहता हूं। आखिरकार मैं निम्नलिखित समाधान के साथ आया। मुझे आज ही यह पता चला (2019-09-26) इसलिए मैं कुछ और लेकर वापस आ सकता हूं अगर यह पता चले कि यह वांछित नहीं है।
इसे अपने प्रोजेक्ट में जोड़ें:
using Windows.UI.Xaml.Resources;
public class MyXamlResourceLoader : CustomXamlResourceLoader
{
protected override object GetResource(string resourceId, string objectType, string propertyName, string propertyType)
{
return MyProject.Language.Resources.ResourceManager.GetString(resourceId);
}
}
इसे App.xaml.cs
कंस्ट्रक्टर में जोड़ें :
CustomXamlResourceLoader.Current = new MyXamlResourceLoader();
आप कभी भी अपने एप्लिकेशन में कहां चाहते हैं, इसका उपयोग भाषा बदलने के लिए करें:
ApplicationLanguages.PrimaryLanguageOverride = "nl";
Frame.Navigate(this.GetType());
UI को रीफ़्रेश करने के लिए अंतिम पंक्ति की आवश्यकता होती है। जब मैं अभी भी इस परियोजना पर काम कर रहा हूं तो मैंने देखा कि मुझे 2 बार ऐसा करने की आवश्यकता थी। पहली बार उपयोगकर्ता द्वारा शुरू किए जाने पर मैं एक भाषा चयन के साथ समाप्त हो सकता हूं। लेकिन चूंकि यह विंडोज स्टोर के माध्यम से वितरित किया जाएगा, इसलिए भाषा आमतौर पर सिस्टम भाषा के बराबर होती है।
फिर XAML में उपयोग करें:
<TextBlock Text="{CustomResource ExampleResourceKey}"></TextBlock>
इसका उपयोग कोणीय में (JSON में कनवर्ट करें)
अब दिनों में घटकों के साथ संयोजन में कोणीय की तरह एक फ्रेम होना अधिक आम है, इसलिए बिना cshtml के। अनुवाद को जोंस फाइलों में संग्रहित किया जाता है, मैं उस कार्य को कवर नहीं करने जा रहा हूं, मैं कोणीय बहु-अनुवाद के बजाय केवल एनएक्सएक्स-अनुवाद की सिफारिश करूंगा । इसलिए यदि आप अनुवादों को JSON फ़ाइल में बदलना चाहते हैं, तो यह बहुत आसान है, मैं एक T4 टेम्पलेट स्क्रिप्ट का उपयोग करता हूं जो संसाधन फ़ाइल को json फ़ाइल में परिवर्तित करता है। मैं सिंटैक्स को पढ़ने और इसे सही ढंग से उपयोग करने के लिए टी 4 संपादक स्थापित करने की सलाह देता हूं क्योंकि आपको कुछ संशोधन करने की आवश्यकता है।
केवल 1 बात पर ध्यान दें: डेटा उत्पन्न करना, उसकी प्रतिलिपि बनाना, डेटा साफ़ करना और दूसरी भाषा के लिए उत्पन्न करना संभव नहीं है। इसलिए आपको कोड के नीचे कई बार जितनी भाषाएं हैं उतनी बार कॉपी करना होगा और '// भाषा चुनें' से पहले प्रविष्टि बदलनी होगी। वर्तमान में इसे ठीक करने का कोई समय नहीं है, लेकिन संभवत: बाद में अपडेट करेगा (यदि रुचि है)।
पथ: MyProject.Language / T4 / CreateLocalizationEN.tt
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".json" #>
<#
var fileNameNl = "../Resources/Resources.resx";
var fileNameEn = "../Resources/Resources.en.resx";
var fileNameDe = "../Resources/Resources.de.resx";
var fileNameTr = "../Resources/Resources.tr.resx";
var fileResultName = "../T4/CreateLocalizationEN.json";
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);
var fileNameDestNl = "nl.json";
var fileNameDestEn = "en.json";
var fileNameDestDe = "de.json";
var fileNameDestTr = "tr.json";
var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();
string[] fileNamesResx = new string[] {fileNameEn };
string[] fileNamesDest = new string[] {fileNameDestEn };
for(int x = 0; x < fileNamesResx.Length; x++)
{
var currentFileNameResx = fileNamesResx[x];
var currentFileNameDest = fileNamesDest[x];
var currentPathResx = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", currentFileNameResx);
var currentPathDest =pathBaseDestination + "/MyProject.Web/ClientApp/app/i18n/" + currentFileNameDest;
using(var reader = new ResXResourceReader(currentPathResx))
{
reader.UseResXDataNodes = true;
#>
{
<#
foreach(DictionaryEntry entry in reader)
{
var name = entry.Key;
var node = (ResXDataNode)entry.Value;
var value = node.GetValue((ITypeResolutionService) null);
if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
#>
"<#=name#>": "<#=value#>",
<#
}
#>
"WEBSHOP_LASTELEMENT": "just ignore this, for testing purpose"
}
<#
}
File.Copy(fileResultPath, currentPathDest, true);
}
#>
यदि आपके पास एक मोड्यूलर एप्लिकेशन है और आपने कई भाषा परियोजनाओं को बनाने के लिए मेरे सुझाव का पालन किया है, तो आपको उनमें से प्रत्येक के लिए एक टी 4 फ़ाइल बनानी होगी। सुनिश्चित करें कि json फाइलें तार्किक रूप से परिभाषित हैं, यह होना जरूरी नहीं है en.json
, यह भी हो सकता है example-en.json
। एनजीएक्स-अनुवाद के साथ उपयोग करने के लिए कई जोंस फ़ाइलों को संयोजित करने के लिए , यहां दिए गए निर्देशों का पालन करें
Xamarin.Android में उपयोग करें
जैसा कि अपडेट में ऊपर बताया गया है, मैं उसी विधि का उपयोग करता हूं जैसा मैंने Angular / JSON के साथ किया है। लेकिन एंड्रॉइड एक्सएमएल फाइलों का उपयोग करता है, इसलिए मैंने एक टी 4 फाइल लिखी जो उन एक्सएमएल फाइलों को उत्पन्न करती है।
पथ: MyProject.Language / T4 / CreateAppLocalizationEN.tt
#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".xml" #>
<#
var fileName = "../Resources/Resources.en.resx";
var fileResultName = "../T4/CreateAppLocalizationEN.xml";
var fileResultRexPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileName);
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);
var fileNameDest = "strings.xml";
var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();
var currentPathDest =pathBaseDestination + "/MyProject.App.AndroidApp/Resources/values-en/" + fileNameDest;
using(var reader = new ResXResourceReader(fileResultRexPath))
{
reader.UseResXDataNodes = true;
#>
<resources>
<#
foreach(DictionaryEntry entry in reader)
{
var name = entry.Key;
var node = (ResXDataNode)entry.Value;
var value = node.GetValue((ITypeResolutionService) null);
if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("&", "&");
if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("<<", "");
#>
<string name="<#=name#>">"<#=value#>"</string>
<#
}
#>
<string name="WEBSHOP_LASTELEMENT">just ignore this</string>
<#
#>
</resources>
<#
File.Copy(fileResultPath, currentPathDest, true);
}
#>
एंड्रॉइड values-xx
फ़ोल्डर्स के साथ काम करता है , इसलिए ऊपर values-en
फ़ोल्डर में अंग्रेजी के लिए है । लेकिन आपको एक डिफ़ॉल्ट भी उत्पन्न करना होगा जो values
फ़ोल्डर में जाता है । बस T4 टेम्पलेट के ऊपर कॉपी करें और उपरोक्त कोड में फ़ोल्डर बदलें।
वहां आप जाते हैं, अब आप अपनी सभी परियोजनाओं के लिए एक एकल संसाधन फ़ाइल का उपयोग कर सकते हैं। यह एक excl दस्तावेज़ को सब कुछ निर्यात करना बहुत आसान बनाता है और किसी को इसका अनुवाद करने और इसे फिर से आयात करने देता है।
इस अद्भुत वीएस एक्सटेंशन के लिए विशेष धन्यवाद जो resx
फाइलों के साथ कमाल का काम करता है । अपने भयानक काम के लिए उसे दान देने पर विचार करें (मुझे इससे कोई लेना-देना नहीं है, मैं सिर्फ विस्तार से प्यार करता हूं)।