Loading...
 
Multi-Language Add-In for Visual Studio

Multi-Language Add-In for Visual Studio


A radical change (for me)

Germany

I have just uploaded a new version (4.70.0000) with several changes.

The Add-In (and also the older VB6 Add-In) has always had a column for the original text and several language columns, including one for the original language.

The need for these two columns, which usually contained the same texts, was always clear to me. In fact it was so clear, that it must have blinded me to how pointless it really was.

In version 4.70 there is no more column for the original text. The original text is shown in the column for the original language.

In principle, this is a small change, but it feels like a radical change to me, because these two columns have been present since the very first version of the Add-In for VB6. The change to the look and feel of the Add-In is surprisingly large. It took me about two seconds to realize that I preferred the new version!

Associated with this change, I have modified the way the Add-In behaves when it detects that an original text has changed. Previously, it showed the text in the original language column in red. This indicated that the texts in the original text and original language columns were different. Obviously, this doesn't make sense if the original text column is no longer present.

Any change to the original text is now automatically copied into the original language (i.e. it is saved as the text for the original language). At the same time, the status of any translations of this text is set to out of date. Out of date translations are shown with red text on a white background. In addition, the previous text is appended to the comment column. This should be eventually be removed when translations are updated (and no longer have the status out of date).

There are a couple more changes in the Excel import/export.

  • The export option only export untranslated strings is now based on the translation status. A text is exported if one or more translations are missing, or if the status of any translation is not spreadsheet import.
  • The import option update status of all texts has the effect that the status of all imported texts is set to spreadsheet import, even if the text is not actually modified by the import.


All of these changes - including the new out of date status - are related to the translation workflow.

Supposing a translator has translated all your texts and you have imported the translations into the Add-In. If you continue to make changes to your project, you may have to send some additional texts for translation. However, there is no need to send all texts in the project back to the translator. All you really want to send are texts which are either new or modified. This effectively means any text where the status is not already spreadsheet import.

Suppose now that you use online translation in the Add-In, before exporting the texts to Excel. The quality of the online translations is not very good, so the translator will correct most of them. However, occasionally there will be a text which is actually correct. Even if the translator doesn't actually change the text, the status effectively changes to checked by the translator. If you know that the translator has checked all texts in the Excel file, it makes sense to set the status of imported texts to spreadsheet import, even if they are not changed.

Finally, version 4.70.0000 also contains a small change to the handling of escape sequences. If you use VB, you can switch off now, because this only concerns C# and C++. The Add-In now processes escape sequences, such as \n, immediately when it scans the source code. Internally, it stores all texts in the unescaped format. If you want to see the escape sequences in the grid, they you can select an option for this in the Add-In setup dialog (it might be the default anyway, I can't remember). In this case, the Add-In will reinsert the escape sequences to show the text in the grid. (I intend to add a similar option to the Excel export soon).

This is actually in preparion for a future change. I intend to make a version which (at least optionally) does not store any texts in the project database. Instead it will store the texts only in the MultiLang.resx file and the localized versions of this file. In this case, the texts must be stored after processing any escape sequences.

By the way, the previous version (4.65.0081) is still available on the download page, in case I have screwed something up badly in the new version. biggrin

Phil

There is no doubt => This is indeed something that will improve the translation workflow by many lengths! I'm looking forward to be testing it later today!

Thank you very much for this update!

Yours Faithfully
Nick Niebling

Germany

Thanks Nick.

Yesterday I completely forgot another change which I made several weeks ago. If you use the Runtime Language Switching feature, then the Add-In generates a function ml_UpdateControls() in each Form or UserControl.

There are now three code generation options for this function, which you can select via the setup dialog:

  • use global resources explicitly
  • use local resources explicitly
  • use local resources implicitly


The only way to explain this is to look at some examples:

GLOBAL resources explicitly
Protected Overridable Sub ml_UpdateControls()
  Me.Text = ml_string ( 3, "About the Simple Editor" )
  btOK.Text = ml_string ( 9, "OK" )
  ToolTip1.SetToolTip(btOK,ml_string ( 8, "Close the dialog" ))
  Label1.Text = ml_string ( 63, "Simple Editor" )
  ToolTip1.SetToolTip(Label1,ml_string ( 6, "The name of the program is ""Simple Editor""" ))
  Label2.Text = ml_string ( 5, "This is a simple editor, based on a TextBox control. It is part of a tutorial for the Multi-Language Add-In for Visual Studio .NET" )
  ToolTip1.SetToolTip(Label2,ml_string ( 4, "This is a description of the program" ))
  lblVersion.Text = ml_string ( 11, "Version" )
  ToolTip1.SetToolTip(lblVersion,ml_string ( 10, "This is the version of the program" ))
  ToolTip1.SetToolTip(PictureBox1,ml_string ( 7, "Picture of trees" ))
End Sub

This is basically the old version. The texts are loaded from the global resource file MultiLang.resx using the ml_string() function.

The other two version both load the texts from the local resource files for the component, <component name>.resx.

LOCAL resources explicitly
Protected Overridable Sub ml_UpdateControls()
  Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(frmAbout))
  Me.Text = resources.GetString("$this.Text")
  btOK.Text = resources.GetString("btOK.Text")
  ToolTip1.SetToolTip(btOK,resources.GetString("btOK.ToolTip"))
  Label1.Text = resources.GetString("Label1.Text")
  ToolTip1.SetToolTip(Label1,resources.GetString("Label1.ToolTip"))
  Label2.Text = resources.GetString("Label2.Text")
  ToolTip1.SetToolTip(Label2,resources.GetString("Label2.ToolTip"))
  lblVersion.Text = resources.GetString("lblVersion.Text")
  ToolTip1.SetToolTip(lblVersion,resources.GetString("lblVersion.ToolTip"))
  ToolTip1.SetToolTip(PictureBox1,resources.GetString("PictureBox1.ToolTip"))
End Sub

In this case, each individual property is loaded explicitly. As you can see, this uses named resources, rather than the numeric String IDs used with ml_string()

LOCAL resources implicitly
Protected Overridable Sub ml_UpdateControls()
  Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(frmAbout))
  resources.ApplyResources(Me, "$this")
  resources.ApplyResources(Me.btOK, "btOK")
  ToolTip1.SetToolTip(btOK,resources.GetString("btOK.ToolTip"))
  resources.ApplyResources(Me.Label1, "Label1")
  ToolTip1.SetToolTip(Label1,resources.GetString("Label1.ToolTip"))
  resources.ApplyResources(Me.Label2, "Label2")
  ToolTip1.SetToolTip(Label2,resources.GetString("Label2.ToolTip"))
  resources.ApplyResources(Me.lblVersion, "lblVersion")
  ToolTip1.SetToolTip(lblVersion,resources.GetString("lblVersion.ToolTip"))
  ToolTip1.SetToolTip(PictureBox1,resources.GetString("PictureBox1.ToolTip"))
End Sub

This final version loads (most) properties implicitly with the ApplyResources() method. This is the technique used in the function InitializeComponent() generated by the form designer. In principle this should be shorter and also more efficient code.

If a single control has multiple properties, then it will generate shorter code (but as you can see above, this might not be true). Extended properties are not loaded by the ApplyResources() method, so these must still be loaded explicitly.

Using ApplyResources() may also load other (non text) properties, such as the size and location of a control. It is possible to define non text properties for individual languages, but the Add-In does not provide any support for it.

All of these versions are functionally equivalent, so it is not really important which one you use. On the other hand, if the texts are stored in a local resource file, it seems consistent and correct always to read them from the local resource file. The third version is essentially the more elegant version.

Phil


> This is actually in preparion for a future change.
> I intend to make a version which (at least optionally) does
> not store any texts in the project database. Instead it will
> store the texts only in the MultiLang.resx file and the localized
> versions of this file.

My heart jumped with joy when reading this. So you are intending to go forward with at least some the changes you proposed in the 'Need for multilang.resx' thread? I firmly believe we're all going to be better for it. Great to see MultiLang climb to the next levels of perfection smile

Thank you for removing 'original language' too, have always wondered what that was for but were afraid to ask in case there was Some Very Good Reason I Failed To See wink