Resource strings are quite irritating.
You have to copy the text into Notepad++ to edit them
Scrolling through large strings is near impossible
When you press F12 on a resource string reference, it brings you to the proxy to the resource store, but no way to edit, nor can you see the full text of long strings.
As more developers fill the list of resource strings, merge conflicts occur more and more on the XML resource files.
Is there a way to stop merge conflicts in the XML resource string files? Is there a better way?
You have to copy the text into Notepad++ to edit them
Visual Studio also provides an XML editor view for resource files. I use this almost exclusively over datasheet view. Give it a try.
Scrolling through large strings is near impossible
Probably easier in XML view.
When you press F12 on a resource string reference, it brings you to the proxy to the resource store, but no way to edit, nor can you see the full text of long strings.
I just use ctrl+F and type in the resource ID.
As more developers fill the list of resource strings, merge conflicts occur more and more on the XML resource files.
Merge problems are greatly reduced if all developers ensure that resources are added or inserted to the file in alphabetical order. We wrote a script to do it and put it into the automated build.
Also, consider organizing your resources into separate files for different purposes, e.g. control labels can go in one file and large text sections can go in a different file. This will reduce contention as well.
Yes, there is - code.
Create a separate static class, I like to suffix "Queries" if it's full of SQL, or "Resources" if it's more general.
In C#, you can use #"", that's enough, but the more recent $#"" is nice if you want to interpolate.
Example:
public class ApplicationStructureCacheQueries
{
public static readonly string ChangeOverNew = $#"
delete from ApplicationStructureCache
insert into ApplicationStructureCache
select * from #NewApplicationStructureCache
";
}
Code Control works very well with line-based coding languages (rather than structured data with multi-line associations - XML). You get the full power of your coding language to work with your strings, including inheritance if you need to (but make it a singleton object, instead of static reference), or perhaps an interpolating function, so it's nice and typesafe and cohesive.
Related
I'm writing custom language service as described in
https://msdn.microsoft.com/en-us/library/bb166533.aspx
Now I'm writing code for AuthoringScope (https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.package.authoringscope.aspx) My problem is in GetDeclarations method.
I have access to text of current file via ParseRequest.Text property.
It allows me to list all methods and variables in my file but how can I access other files content? I need to get access to other file content for building AST tree of this file but I don't know how can I do this.
Personally I find the MPF "helper" classes (like AuthoringScope) to be a bit restrictive, and implement everything manually (which, I admit, does take more time, but is a lot more flexible in the end).
In any case, it sounds like your language (like most!) has dependencies between files at the semantic parsing level. This means you'll either have to:
a) reparse a lot of text all the time, which is likely too slow in large projects
or b) maintain a global aggregate parse of a project's files, and update it dynamically when the files (or the project's properties) change
b) is obviously a lot harder, but is almost certainly the best way to do it. A general outline would be to discover all projects after a solution is opened via EnvDTE, parse them all (discover all files in each project, again via EnvDTE), and store everything in some sort of indexable data structure so that you can do fast queries against it (for semantic syntax highlighting, go to definition, etc.). Then you need to listen for changes everywhere and reparse appropriately -- you'll need to check for solution open/close (IVsSolutionEvents), projects being added/removed/renamed/unloaded/loaded (IVsSolutionEvents/IVsSolutionEvents4), files being added/removed/renamed (IVsHierarchyEvents), files being edited (IVsTextViewCreationListener + ITextBuffer.Changed), and project configurations changing (IVsUpdateSolutionEvents, IVsHierarchyEvents).
Whether you choose a) or b), you still need to be able to check if a file is opened in the editor (potentially with unsaved changes) or not. You can check if a file is already open in the Running Document Table (but don't forget to normalize the path first using Path.GetFullPath()) via the IVsRunningDocumentTable service, which will return an IntPtr to the document data, which can be coaxed into yielding an ITextBuffer for the file, which contains the text (and entire buffer history!) of the file. Of course, if it's not open you'll have to read it from disk.
I am currently creating a console applications that only accepts some commands defined by me. The thing is I'm storing a lot of error and notification messages on a static class I created called Messages and then just calling them like Messages.ErrorMessage.... ErrorMessage is just a static string that contains w/e I want printed on the console.
What I wanted to ask is if that's a good way of implementing such behavior or should I instead change where I'm keeping all of this Messages?
Thanks for your help!
I guess for your need you can use Resource file instead of static class.
as documented on official site
Visual C# applications often include data that is not source code.
Such data is referred to as a project resource and it can include
binary data, text files, audio or video files, string tables, icons,
images, XML files, or any other type of data that your application
requires. Project resource data is stored in XML format in the .resx
file (named Resources.resx by default) which can be opened in Solution
Explorer.
For more information :-
http://msdn.microsoft.com/en-us/library/7k989cfy(v=VS.90).aspx
As suggested by others, storing them in resource files is the recommended way to deal with such resources, particularly if you'll need to deal with internationalization. then you can load a different resource file from a satellite assembly at run time with the correct information.
You will notice a slight performance hit as the strings will be looked up in a resource dictionary, but usually that is negligible.
It is my first time to use resx file to store strings in Visual Studio. It's so weird that when I modified something on designer.cs, and saved it, all strings in resx were gone. Does anyone meet this issue before? How to solve it? Thanks!
You should not edit Form.resx files manually. Together with Form.Designer.cs files they should only be edited with the use of winform designer.
Form.resx and Form.locale.resx files contains all resources associated with that form controls: icons, cursors, images, localization strings, etc.
If you need to put custom resources, then simply create separate resx-files (see here of how to work with them).
It is still a question, if you really need to use resource files. Having static class to store strings is much more comfortable way, you will have all power of intellisence (find all references, no spelling errors, etc), while accessing resources required specifying identificator, where you can very easily make a mistake or two. If you think about localization, then it's different story (but still, you can use reflection and text-files to have it way more comfortable then microsoft satellite way).
Form.resx is only used by WinForms designer, so leave it alone in all cases.
The contents stored in such designer managed resource files can be,
Form icons
Control tooltips if their contents are longer than a predefined length
ImageList contents
and many other (which is undocumented)
Like #Kilazur pointed out, you should store your own resources in newly created resource files that are not controlled by the designer.
I want my C# (winforms) application to be multilingual. My idea is:
I will have my translations in some text file(s), each "sentence" or phrase will have it's unique ID (integer)
at the start-up of the app I will iterate through all controls on all forms I have in my app (I suppose this should be done in each form's 'Load' event handler) and I will test the control of it's type
i.e. if it is a button or menu item, I will read it's default 'Text' property, locate this phrase in one text file, read it's unique ID and through this ID will locate translated phrase in (other) text file
then I will overwrite that 'Text' property of the control with translated phrase
This enables me to have separate text file with phrases for each and every language (easy to maintain individual translation in the future - only 1 txt file)
I would like to hear from you - proffesionals if there is some better / easier / faster / more 'pro' way how to accomplish this.
What format of translation text file should I use (plain text, XML, ini....) - it should be human readable. I don't know if finding a phrase in XML would be in C# faster than going line-by-line in plain text file and searching for given phrase/string...?
EDIT - I want users (community) to be able to translate my app for them into their native language without my interaction (it means Microsoft's resources are out of the game)
Thank you very much in advance.
CLOSED - My solution:
Looks like I'm staying at my original concept - every phrase will be in separate line of plain text file - Unicode encoding (and ID at the beginning of the line). I was thinking about deleting ID's too and to use only the line numbers, but it would need advanced text editor (Notepad shows no line numbers) and if somebody accidentaly hits shortcut for "Delete line" and doesn't notice that, whole app would go crazy :)
//sample of my translation text file for one language
0001:Text of my first button
0002:Text of my first label
0003:MessageBox title text
...etc etc
Why not use Microsoft's resource file method? You won't need to write any complex custom code this way.
It sounds like you are somewhat invested in the "one text file" idea, or else you would probably lean towards the standard way and use Microsoft's resource files. Handling for resource files is built-in, and the controls are already keyed to support it. But, as you are probably aware, each translation goes into it's own resource file. So you are left juggling multiple files to distribute with your app.
With a custom, roll-your-own solution, you can probably trim it down to one unicode file. But you will have to loop through the controls to set the text, and then look up the text for each one. As you add control types, you will have to add support in your code for them. Also, your text file will grow in large chunks as you add languages, so you will have to account for that as well.
I still lean towards using the resource files, but your phrasing suggests you already don't like that solution, so I don't think I have changed your mind.
Edit:
Since you want the solution separated from the app to avoid having to recompile, you could distribute SQL-CE database files for each language type. You can store the text values in NVARCHAR fields.
That will make your querying easier, but raises the self-editing requirements. You would have to provide a mechanism for users to add their own translation files, as well as edit screens.
Edit 2:
Driving towards a solution. :)
You can use a simple delimited text file, encoded in Unicode, with a convention based naming system. For example:
en-US.txt
FormName,ControlName,Text
"frmMain","btnSubmit","Save"
"frmMain","lblDescription","Description"
Then you can use the CurrentUICulture to determine which text file to load for localization, falling back to en-US if no file is found. This lets the users create (and also change!) their own localization files using common text editors and without any steep learning curve.
If you want the users to edit the translations through your application while keeping things simple and quick, resource file is best. If you don't like it, the second best option is XML file.
Still, to answer you question on how to do it best with a text file, it is pretty straight forward: You just make sure that your unique identifier (int probably) are in order (validate before using the file). Then to search quickly, you use the technique of the halves.
You look for number X, so you go to the file's middle line. If id > x, to go to ΒΌ of the file, etc.
You cut in two until you get to the right line. This is the fastest know research method.
NOTE: Beware of the things that are external to the application but need translation: External file items, information contained in a database, etc.
We have some auto-generated resource files in our project in Visual Studio 2008, with some localized versions, and in one of these localized versions, there is a string which in this case is empty.
More explicit. We have a core resource file, with lots of string resources. We then have 4 other localized versions of thisfile, and in one of these other localized files, one of the strings is given an empty value.
The problem now is that the form designer is quite happy about having found a resource for a string, and will apparently stop at nothing for reusing this resource for any empty strings it will assign a property in the generated designer code for a form.
For instance, if for some reason a property on a control is not specified with a default value (so it will be serialized to code even if it is empty), then it will reference our resource instead of writing out the empty string literal in the C# code.
Problem is that it references the localized versions, and these aren't compiled to code.
Here's an abbreviated code example:
this.rpAllFields.KeyTip =
global::namespaces.SystemMessagesResources_sv_SE.
dash_red_shift_info_description;
In this case, the dash_red_shift_info_description does not have a value for the sv-SE locale, so the designer, when it sees an empty string in the code, will try to link to that resource. But the SystemMessagesResources_sv_SE isn't an existing class, but seemingly a generated class name for the swedish localized version of the SystemMessagesResources resource file, which is compiled to a class.
Is this possible to avoid? We're getting rather tired of the search/replace each time we change something in the form files, and we're pretty sure there's a slap-my-forehead-boneheaded thing we've done that make this happens, but we're aparently not capable of finding the cause of this ourselves.
The above code would, if we removed the resource, read like this:
this.rpAllFields.KeyTip = "";
You might try creating a string resource empty_string, defined as "" for every locale. If you make it the first resource, the form designer will (hopefully) always pick that one as the value to sprinkle through your forms. This way at least you'll be using a string designated for that purpose.
If the problem is being caused by an empty string in the resource file, what would the effect be of making it a space. So instead of "" the resource file contains " ". I don't know if that's the best solution but I would be interested to know if it stops the designer from using that resource as a default empty string. However, not knowing how it is used, I'm not sure what the impact of having a value that should be undefined be defined as a space...
How much do you need a resource whose value is an empty string? I can imagine some multilingual scenarios where some resource key should correspond to blank in some of the supported languages (if you are using string concatenation for some UI elements), yes.
But if MY scenario wasn't something like this, I would just scrap the resource entry with the empty string. I'd just say, "What standalone UI text translates to blank, anyway?".
If I really needed the resource to be blank in some cases, (where it stands for an article in one language and where no equivalent word exists in another), I would try to see if I could produce the same effect some other way.
Generated resource file and code sample would be good.
And what you are saying is: you have an empty string literal definition in your namespace (the first one found) but that is causing some problem? Won't it be empty at all times? When you compile the code- it does quirky things like this to save space. I ran into a similar issue when generating XAML files with codebehind for on-the-fly automated build of assembly files: The compiler is smart enough to know 'it doesn't make a difference but for us it did because it would rename the literals (which were used elsewhere).
To work around this we used named types for these primitives in our namespace and made that one global. What I see here is that your global namespace is filling in the blanks- you may want to have one 'below' which evaluates all null strings.
I haven't worked with this in over a year so forgive me if my wording is poor, but what i mean is: think XML. You need to either explicitly use namespace in the properties or assign them lower (like attached property in xaml).
I hope this helps (and makes sense)