How to use STRINGTABLE with a Python Command Plugin



  • Hello,
    I'm trying to add multi-language support in my plugin.

    I currently have the strings hardcoded in the GeDialog's CreateLayout method like this:

    self.AddStaticText(self.HELP_ID, c4d.BFV_BOTTOM | c4d.BFV_SCALE | c4d.BFH_LEFT, 0, 0, "Help")
    

    All of the strings are labels for UI menu commands and gadgets. I understand that the best practice is to put the UI strings into folders within a 'res' folder like so:

    res
    └ strings_en-US
        └ c4d_strings.str
    └ strings_fr-FR
        └ c4d_strings.str
    

    My issue is I don't know how to use the STRINGTABLE in the .str with my Python CommandPlugin. Here's an example of the c4d_strings.str content:

    c4d_strings.str (strings_en-US)

    STRINGTABLE
    {
    	IDS_TEST "Test Plugin";
    	TITLEVIEW_ID "Test - View";
    	
    	HELP_ID "Help";}
    }
    

    c4d_strings.str (strings_fr-FR)

    STRINGTABLE
    {
    	IDS_TEST "Test Plugin";
    	TITLEVIEW_ID "Test - Vue";
    	
    	HELP_ID "Aide";
    }
    

    Please forgive all of these questions:

    • What is the best practice for loading these STRINGTABLES and using them in the UI? I couldn't find an example using a CommandPlugin in the official Cinema 4D Python examples though I did see that the py-ies_meta_r12.py SceneSaverPlugin example uses a method called c4d.plugins.GeLoadString.
    • If GeLoadString is the way to go, would I set up my IDs in my GeDialog class and reference the corresponding ID in the STRINGTABLE with this method?
    • Would Cinema 4D then grab the correct string based on the user's language if my folder structure is set up appropriately?
    • Is there a similar method for automatically handling the localized date and time format?
    • As mine is not an Object plugin, I won't need a description folder, is that correct?
    • What should I do with the c4d_symbols.h file?

    Thank you so much!



  • Hi, @blastframe as @PluginStudent pointed you should use GeLoadString.

    To make GeLoadString working, you should use as you already did, the .str file but also the c4d_symbols.h so this way Cinema 4D can link the ID you provided in the str file to an actual int value.

    res
    └ c4d_symbols.h
    └ strings_en-US
        └ c4d_strings.str
    └ strings_fr-FR
        └ c4d_strings.str
    

    c4d_symbols.h

    enum
    {
    	IDS_TEST = 10000,
    	TITLEVIEW_ID,  // This will have id 10000 + 1
    	HELP_ID, // This will have id 10000 + 2
    	
    	// End of symbol definition
    	_DUMMY_ELEMENT_
    };
    

    However, due to the nature of Python, the int value defined in the c4d_symbols.h is not ported to python so you have to redefine it in your python code as well.

    And here is how to use it in your pyp file. This needs the __res__ to be defined, this is done automatically, for more information see Issue with registering a ToolData.

    print c4d.plugins.GeLoadString(10000) # Will print the str value of IDS_TEST 
    

    Finally, note that these Symbol IDs must be unique through all Cinema 4D so instead of IDS_TEST is would recommend you rename it with BLASTFRAME_IDS_TEST.

    Cheers,
    Maxime.



  • GeLoadString() is the way to go. You actually find plenty of examples of GeLoadString() being used in the C++ code base (e.g. asynctest.cpp) and this doc: String Manual (Classic).



  • Hi, @blastframe as @PluginStudent pointed you should use GeLoadString.

    To make GeLoadString working, you should use as you already did, the .str file but also the c4d_symbols.h so this way Cinema 4D can link the ID you provided in the str file to an actual int value.

    res
    └ c4d_symbols.h
    └ strings_en-US
        └ c4d_strings.str
    └ strings_fr-FR
        └ c4d_strings.str
    

    c4d_symbols.h

    enum
    {
    	IDS_TEST = 10000,
    	TITLEVIEW_ID,  // This will have id 10000 + 1
    	HELP_ID, // This will have id 10000 + 2
    	
    	// End of symbol definition
    	_DUMMY_ELEMENT_
    };
    

    However, due to the nature of Python, the int value defined in the c4d_symbols.h is not ported to python so you have to redefine it in your python code as well.

    And here is how to use it in your pyp file. This needs the __res__ to be defined, this is done automatically, for more information see Issue with registering a ToolData.

    print c4d.plugins.GeLoadString(10000) # Will print the str value of IDS_TEST 
    

    Finally, note that these Symbol IDs must be unique through all Cinema 4D so instead of IDS_TEST is would recommend you rename it with BLASTFRAME_IDS_TEST.

    Cheers,
    Maxime.



  • Since this topic is older than a week I marked is as closed, but feel free to reopen it if you have further questions.

    Cheers,
    Maxime



  • @m_adam Hi Maxime! I wanted to make sure I had all of my strings before implementing this. I am very grateful for your help. I will come back to this thread soon! Thank you!



  • @m_adam I got it working with your help! Thank you so much. I have a couple more questions (more for advice really):

    1. Are there tools for creating C++ STRINGTABLES like the ones Cinema 4D uses?
    2. I am currently using a spreadsheet for editing my stringtables. Are there any tools I can use to export the non-ascii characters as unicode that Cinema 4D will understand?
      Thank you!


  • I don't think there are any official "tools". But the docs describe how to handle unicode (Dialog Layout):

    The encoding is 7-bit ASCII with other characters encoded as \uHHHH. For example 'Natürlich' is written 'Nat\u00fcrlich'. Byte-order marks are not used.


Log in to reply