Search code examples
.netvisual-studioglobalizationresx

Put translated resx files in a different folder in Visual Studio?


I've got a solution with 14 translations and 12 files and the "Resources" folder is getting a bit out of hand. Is there a way to put the translated files into a different folder so I can access the master English ones more easily?

I've noticed that you can change the namespace the designer file is generated in by setting the Custom Tool Namespace, but I haven't figured out how to pick up translations from a different folder. I toyed with the idea of using links to make a "shortcuts" folder and a "real" folder but you can't link to a file within the project structure and you can't link to the same file twice outside of the project structure. I thought about changing the namespace that the ResourceManager used based on the language but that would break the fallback behavior.

Is there any way to manage this so it isn't a giant list of files in Solution Explorer?


Solution

  • Let's say you want to place all the translated .resx files in a Translations folder, like this (note I have left the default and en versions in the root folder):

    enter image description here

    Then all you need to do is edit the MSBuild project file (from Visual Studio, right-click on the project node, 'Unload project', then 'Edit xxx.csproj'), and reconfigure each Resx file in this folder like this:

    before:

      <ItemGroup>
        ...
        <EmbeddedResource Include="Resource1.en.resx" />
        <EmbeddedResource Include="Translations\Resource1.fr.resx" />
        <EmbeddedResource Include="Resource1.resx">
          <Generator>ResXFileCodeGenerator</Generator>
          <LastGenOutput>Resource1.Designer.cs</LastGenOutput>
        </EmbeddedResource>
        ...
      </ItemGroup>
    

    after:

      <ItemGroup>
        ...
        <EmbeddedResource Include="Resource1.en.resx" />
        <EmbeddedResource Include="Translations\Resource1.fr.resx">
          <ManifestResourceName>$(TargetName).%(Filename)</ManifestResourceName> <!-- add this for all .resx files in a custom folder -->
        </EmbeddedResource>
        <EmbeddedResource Include="Resource1.resx">
          <Generator>ResXFileCodeGenerator</Generator>
          <LastGenOutput>Resource1.Designer.cs</LastGenOutput>
        </EmbeddedResource>
        ...
      </ItemGroup>
    

    What it does is instruct underlying MSBuild tasks to use the manifest name you specificy instead of generating one automatically. The automatically generated one always uses the folder layout where the RESX resides in which is not what we want.

    After compilation, the final satellite ConsoleApplication1.resources.dll file will be placed in the fr folder as usual, but its content will be the same as if the resx file was placed in the root folder.