Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    How can I add a menu to .res file for muti-language support?

    Cinema 4D SDK
    s26 python windows
    2
    14
    1.4k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • DunhouD
      Dunhou @ferdinand
      last edited by

      @ferdinand

      Thanks for the detailed explain.

      It seems I should add the menu and menu botton in the .res file for use this .str file.

      Now the main GUI already worked , but I didn't find a way to add menu or button in .res file. or reg a unvisibale text in dialog.res .

      Did I understand something wrong , could you privide a mini code for this?

      My didn't work code:

      **IDS_MY_STRING** : { IDS_MENU   "My Test"; }
      **c4d_symbols.h** : enum {   _FIRST_ELEMENT_ = 20000,     IDS_MENU,   _DUMMY_ELEMENT_ };
      **plugin.pyp** : myLocalizedString: str = c4d.plugins.GeResource.LoadString(IDS_MENU)
      

      https://boghma.com
      https://github.com/DunHouGo

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @Dunhou
        last edited by

        Hello @dunhou,

        this defintion seems mostly correct, the file IDS_MY_STRING should however be named c4d_strings.str. You put there the general prupose string defintions for a language (e.g., strings for menus).

        In Python you must also manually expose the symbols for your string as Python is not importing automatically them automatically as C++ does. So, when your symbols defintions is

        c4d_symbols.h

        enum {   
        //_FIRST_ELEMENT_ = 20000 // Not really required
        IDS_MENU, 
        _DUMMY_ELEMENT_ 
        };
        

        then you must either define in your Python file somewhere that IDS_MENU: int = 20001 or use the raw integer value in calls instead.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        DunhouD 1 Reply Last reply Reply Quote 0
        • DunhouD
          Dunhou @ferdinand
          last edited by

          @ferdinand

          I try to do this but it report a bug , here is a more part of codes:

          plugin.pyp

          ID_MB = 100 # button ID
              def CreateLayout(self):
                  IDS_MENU: int = 20002 # MENU str ID in c4d_symbols.h 
                  myLocalizedString: str = c4d.plugins.GeResource.LoadString(IDS_MENU)
                  # buttton in menu
                  if self.GroupBeginInMenuLine():
                      self.AddButton(self.ID_MB, c4d.BFH_LEFT | c4d.BFV_TOP, name=myLocalizedString)
                  self.GroupEnd()
                  return self.LoadDialogResource(20001) # DIALOG ID in c4d_symbols.h 
          

          c4d_symbols.h

          enum {  
          _FIRST_ELEMENT_ = 20000,    
          IDD_DIALOG,
          IDS_MENU,   
          _DUMMY_ELEMENT_ 
          };
          

          IDD_DIALOG.res in resources :

          DIALOG IDD_DIALOG
          {  
            NAME IDS_DIALOG; SCALE_V; SCALE_H; 
          }
          

          c4d_strings.str in strings_en-US/dialogs folder

          {
            IDS_DIALOG    "Title";
            IDS_MENU   "button1";
          }
          

          console reports

          myLocalizedString: str = c4d.plugins.GeResource.LoadString(IDS_MENU)
          TypeError: descriptor 'LoadString' for 'c4d.plugins.GeResource' objects doesn't apply to a 'int' object
          

          Thanks

          https://boghma.com
          https://github.com/DunHouGo

          1 Reply Last reply Reply Quote 0
          • DunhouD
            Dunhou
            last edited by

            sorry for my bad internet those days,It will duplicate post sometimes

            https://boghma.com
            https://github.com/DunHouGo

            1 Reply Last reply Reply Quote 0
            • ferdinandF
              ferdinand
              last edited by ferdinand

              Hello,

              eh, my bad I overlooked that you were using an incorrect call for loading the string. Since you you are in the pyp file, you do not have to init the ressource yourself, as the module attribute __res__ of that file already contains it (just put a print(__res__) anywhere in your code in the pyp file, and you will see that it is a GeResource instance).

              In your case you just have to use

              myLocalizedString: str = c4d.plugins.GeLoadString(IDS_MENU)
              

              which will then use the resource __res__ which has been build automatically by Cinema 4D for your plugin. It is only when you are outside of that pyp file, that you must build the GeResource

              When you are in such scenario or just want to generally load a custom resource, it will work something like this:

              resource: c4d.plugins.GeResource = c4d.plugins.GeResource()
              # resourcePath is the root folder of where the resource is located. E.g., you have the plugin MyPlugin
              # at the directory /MyPlugin with a directory /MyPlugin/res in it, then resourcePath would be /MyPlugin
              resource.Init(resourcePath)
              
              # You can then either expose this resource as the module resource and then use c4d.plugins.GeLoadString
              # as in a pyp file.
              global __res__
              __res__: c4d.plugins.GeResource = resource
              myLocalizedString: str = c4d.plugins.GeLoadString(IDS_MENU)
              
              # Or use the resource instance directly.
              myLocalizedString: str = resource.GeLoadString(IDS_MENU)
              

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              DunhouD 1 Reply Last reply Reply Quote 0
              • DunhouD
                Dunhou @ferdinand
                last edited by

                @ferdinand

                Sorry to reply late. Little busy before.

                I am a little confused , in python document Plugin Structure , This page said plugin structure like this:
                b3bfa8f7-9ce3-4e82-b572-115fab70cf0a-image.png
                It's different with the structure above.

                And another problem is : In my mind , string_us/dialogs/IDD_DIALOG.str , this str file define the dialogs texts string , but the string_us/c4d_strings.str file , It's a little confused , is it define the strings in the menu of the dialog? If it is , how can I set the ID of this string ?

                And in the code above, myLocalizedString: str = c4d.plugins.GeResource.LoadString(20002) , this line cann't find a string in IDD_DIALOG.str with the ID(int) in c4d_symbols.h .
                7522b224-c6e6-417e-afb2-34213e6b29dd-image.png

                https://boghma.com
                https://github.com/DunHouGo

                ferdinandF 1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand @Dunhou
                  last edited by

                  Hello @dunhou,

                  You are right, my little diagram was not correct, the string folders must be part of the resource, I forgot to indent them one level. I have fixed the diagram.

                  The string definitions in language\dialog, e.g., string_us/dialogs/myDialog.str, define the strings referenced by a dialog definition, e.g., dialogs/myDialog.res. E.g., when you have some dialog gadget which is defined to have NAME IDS_MY_GADGET in myDialog.res, the myDialog.str files for all languages must define a string IDS_MY_GADGET.

                  The file c4d_strings.str on the other hand is used to store generic string, and it is not specifically made for menus, it is just one way you can use it. There is no (public) mechanism to define menus in resources, so, all you can do is to define strings in the c4d_strings.str files and then load strings for the currently active language inside Cinema 4D to build a localized menu out of them.

                  You can see this multipurpose nature at the example of the strings_en-US/c4d_strings.str file of the Asset API Examples Plugin. I stored there all kinds of string information, ranging from tooltips, over the names of the examples and their short descriptions, to some URLs. c4d_strings.str does exactly what its name implies, it stores generic strings.

                  I hope this clarifies things.

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  DunhouD 1 Reply Last reply Reply Quote 0
                  • DunhouD
                    Dunhou @ferdinand
                    last edited by

                    @ferdinand

                    A lot of appreciate!

                    It works very well , I found when I have a c4d_strings.str , the myDialog.str must have SAME name as myDialog.res . If it doesn't have a c4d_strings.str file and work with only one dialog , the myDialog.str can have another name and it works well too.

                    (I am not sure this qustion should be post there or in a new blog😢 )
                    And a little thing I am not sure is : those ID form c4d_symbols.h contain the ID of text/bitmap/button/... , in this case main dialog ID is 20000 , but if I have mutiple dialogs or sub dialogs from the main dialog(even another plugins), what is happend if those dialog's ID contain some same numbers?

                    https://boghma.com
                    https://github.com/DunHouGo

                    ferdinandF 1 Reply Last reply Reply Quote 0
                    • ferdinandF
                      ferdinand @Dunhou
                      last edited by ferdinand

                      Hey,

                      but if I have mutiple dialogs or sub dialogs from the main dialog(even another plugins), what is happend if those dialog's ID contain some same numbers?

                      You cannot do that, all integer identifiers for dialogs within a project (i.e., stuff the is located in the same resource directory) must be unique. Except for cycle values, they only do have to be unique within the scope of the cycle/dropdown they are being defined for.

                      If you really want to have two dialogs which share ID values for gadgets, then you must define them in different projects, each with their own resource directory. Which will also mean that the two dialogs cannot access each other's implementation (in an easy manner, you could of course cook something up with messages for example).

                      Cheers,
                      Ferdinand

                      MAXON SDK Specialist
                      developers.maxon.net

                      DunhouD 1 Reply Last reply Reply Quote 0
                      • DunhouD
                        Dunhou @ferdinand
                        last edited by

                        @ferdinand

                        Is that means if I have a plugin A with unique ID A , the dialog ID 100 likes A-100 inside , and plugin B with unique ID B , the dialog ID 100 likes B-100 , so that they can exist at same time ?

                        And those A-100 like IDs will dispear when close c4d , so I don't have to unreg them :eg.: bitmapbutton IDs manually? ( c4d.gui.RegisterIcon / c4d.gui.UnregisterIcon)

                        https://boghma.com
                        https://github.com/DunHouGo

                        1 Reply Last reply Reply Quote 0
                        • ferdinandF
                          ferdinand
                          last edited by

                          Is that means if I have a plugin A with unique ID A , the dialog ID 100 likes A-100 inside , and plugin B with unique ID B , the dialog ID 100 likes B-100 , so that they can exist at same time ?

                          Yes, other than plugin IDs, resource IDs are scoped within the resource they are being used for. plugin A is simply not aware of the resources of plugin B.

                          And those A-100 like IDs will dispear when close c4d , so I don't have to unreg them :eg.: bitmapbutton IDs manually? ( c4d.gui.RegisterIcon / c4d.gui.UnregisterIcon)

                          You do not have to register or unregister anything in this context.

                          Cheers,
                          Ferdinand

                          MAXON SDK Specialist
                          developers.maxon.net

                          DunhouD 1 Reply Last reply Reply Quote 0
                          • DunhouD
                            Dunhou @ferdinand
                            last edited by

                            @ferdinand

                            Thaks for all of that explains .

                            With your detailed and friendly explains , A new habbitor like me can code within Cinema 4D as well . Thanks for that !🤣

                            https://boghma.com
                            https://github.com/DunHouGo

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post