I am trying to figure out whether a global string resource file for the entire application or a local resource file for each small sub area would be a better choice.
It seems like a translator would appreciate the one file approach vs hundreds of them. It is also easier to write helper functions since there is only going to be one static resource class.
The downside is that the resource name might be really long to properly identify the place where it is suppose to be in and it might be hard to locate related strings when the file grows big.
Where as a local resource file would produce lots of duplicated strings or make it confusing if we need to use multiple instances of static resource classes because the strings are spread between multiple of them.
So what would be a better way to go?
Maybe you could break your resources into 3 files (depending on your application design):
ResourcesCore
For translated enum values and common expressions
ResourcesEntity
For strings related to translation of some entity properties (e.g. Person.Name)
ResourcesWeb (or ResourceUI)
For other UI related stuff (like strings on UI, labels, descriptions, etc.)
You could then use ResXManager extension for VS to manage you resource strings (way easier than native .NET ResX manager, at least for me).
Related
I'm trying to figure out how to choose between two different (identically designed) Resources files in code. All of the examples I can find online are in reference to having different language specific Resource files which are chosen based on setting the culture value. That won't work for my probelm.
This is a web service which returns an image from one of several different image repository systems. Depending on a parameter passed in to the method, the service will need to access an image repository system in order to pull the image being requested. When accessing the image repository, there are a bunch of "magic string" GUID values that represent different IDs for various lookups in that system. One of the purposes of this service is to hide all of that complexity from the user. Rather than hard-code these GUIDs into the code, I have put them into a Resources file.
The problem is this: Each different image repository system has the same set of magic string IDs that need to be used. However, the actual GUID values for these magic strings are different depending on which repository you are connecting to. For example, there is a value called "GroupIDPrompt" which might be "8a48f393642a753f0164418b670a7cdf" on one system, but "63aa28c3637b58680163b25f7e5a5d96" on a different system. In code, I'd like to refer to this value as just "Resources.GroupIDPrompt" or something similar, but I need to be able to set which Resources file will be used at runtime, based on what the consumer of the service sent me.
Normally, I might solve a problem like this by using an interface, and instantiating a specific implementation of that interface based on the request. There are two reasons that doesn't work here - #1, Resource code files are generated automatically, and if I edit them to make them inherit from an interface, this will get broken everytime the file is regenerated. #2, All resource values are created to be static members, and interfaces aren't allowed to declare static members.
I could throw the Resources files away and instead build a class to expose these values, but that means re-introducing magic hard-coded strings to my code. That isn't too terrible, I suppose, but the Resource editor is really quite handy for managing and editing these values.
So I have files that are used in multiple projects (in one solution). Which way would I choose?
Embedded Resource and use with Assembly.GetManifestResourceStream
Add file to Resources.resx and use with Properties.Resources.
Copy to Output Directoryand use the known path to read
Linked Resource?
Right now the files reside inside a Resource-Folder in the root directory of the solution. But this way there is no relative path to these files.
I could add them to properties/resources but to which project? There is no "main" project that handles these files. Or create a new "ResourceHolder"-project just for resources?
If I add them to multiple projects they are all copies and not links to the original file/path as far as I know... so that's also no option.
Can't you add resources solution wide? Or better have a solution wide folder and only if a project uses a file it is then copied to output and can be used with a relative path?
There are no solution-wide resources, because there is no artifact produced by the solution itself. The place to put the resources depends, in my opinion, on the semantics of the resources.
If they are, for example, icons, which must be consistent over several assemblies (i.e. over several controls that reside in different assemblies or several different applications belonging to a set of applications), then they semantically are global resources. Hence, I would put them into a separate resource assembly that is referenced by all other assemblies.
If they are separate resources that just happen to be the same right now (i.e. test data for different test assemblies), then they have, in my opinion, no global semantics and should be copied into every project which requires them. This would then also allow to distribute the resulting assemblies independently as they have no further dependencies on each other.
Regarding your third option: I would always try to avoid working on files directly. This only may be applicable in two scenarios:
First, if the files do not belong to the application, i.e. they are user data (such as documents read and written by the application); that doesn't seem to be the case her.
Second, if the files are so large that duplicating them would result in a substantial demand of disk space. Your question does not read like that's the case, but in such a situation it might be feasible to provide a central repository of the data.
I am building a multi-language MVC application and have a series of resource files with translated strings for messages that will be displayed to the user.
Is there any way of ensuring that any resource files added in the future have all required keys and are spelled correctly?
As an analogy, if the resource file was a regular class, you could provide an interface to ensure that all required method and properties were present in the implementing class. Is there a similar concept for resource files?
I've been unable to find a supported way to enforce an explicit contract upon a .resx file. Since your goal is ultimately to catch implementation errors before they show up at runtime (and compile time checking isn't possible), I recommend falling back to static code analysis. Luckily, .NET makes this trivially easy:
Use the System.Resources.ResXResourceReader class to read the contents of the resx files to be validated.
Implement a test that asserts against all required keys in the "contract" you'd like to enforce on the resx.
Test should run as part of an existing test suite, and failure will warn a developer of the implicit contract before encountering the problem at runtime.
Since your resource files will exist in a known location, you can trivially ensure that the tests run against all resx files in that directory. In this way, you don't even need to update the test when new resource files are added, only if the contract changes.
I've used a similar approach to help with maintenance of stored procedure names kept in (an extensive number of) resx files. Since the resource files are spread across dozens of projects, manual maintenance is tedious and error-prone -- in other words, it doesn't get done. The static code analysis approach has yielded few downsides, and I think it would work well in your case as well.
Landing page for resource files on MSDN
ResXResourceReader on MSDN
System.Resources.ResXResourceReader requires a reference to System.Windows.Forms. It's available on both .NET and Mono.
I work on a product where we have to worry a bit about localization. Currently, this is the workflow for when I have to use(or add) a localized string:
Search resources.resx file(which has hundreds of items)
If found, then copy the name. Otherwise, add a new string and copy the name
Then, use ResourceFactory.ResourceMgr.GetString("MY_MAGIC_STRING") (where ResourceMgr is just a static field to a ResourceManager)
This 3 step process for any strings is a real pain. Are there any patterns or ways to make this process easier?
Auto-generated files with access to each individual string are much easier to use - set "Custom tool" for RESX file to PublicResXFileCodeGenerator.
Code would look like:
using MyProject.Resources;
...
localizedText = Resources.SomeReasonableName;
Side notes:
having multiple RESX files along with auto-generated IDs have additional benefit of intellisense giving you reasonable number of choices.
depending on how translation is handled you may be better not worrying about duplicated text in RESX file (except maybe OK/cancel kind of strings). It may be easier to deal with duplicated strings at translation time.
There is this Java solution that might give you some ideas:
http://rodionmoiseev.github.com/c10n/
The idea is to store translations in the source code itself, using annotations on interface methods. Then, by using a special utility, you can dynamically create proxies (classes dynamically implementing the interface) that would return localised string value when invoking the interface method.
This way, "MY_MAGIC_STRING" is replaced with a call to MyMagicString() method, which gives you some spelling/type safety and makes it more refactoring friendly.
Where is the best place to put string literals within the class? Should they be declared as constant members, should they be referenced in the method (provided the string literal is only ever used once), should they be put in a helper class or elsewhere?
Are you referring to strings that are displayed to user and require internationalization?
In .NET and Java you can use Resource Files that lets you use a key/value resource file. This has the added advantage of not needing compilation every time you need to change text, and you don't need to be a coder to be able to modify the resource files.
If you're just talking about internal strings that are used (like keys, IDs etc.) then I wouldn't fuss too much about it - some people like "constants.cs", while other like it within the file that is using them, and others like putting each set of constants in their own relevant packages. Just keep it ... Constant.