MDGP October 2019 Release Feature of the Day: User Access Enhancements

Microsoft Dynamics GPThe Inside Microsoft Dynamics GP blog has started a series Feature of the Day posts for Microsoft Dynamics GP “October 2019” Release on which I am following and adding commentary. The index for this series of posts is here.

The fifth Feature of the Day is User Access Enhancements.

There are four enhancements to the User Access window. Firstly, you can choose to filter inactive users from displaying in User Access Setup. This is a per user setting and will be saved the next time you open the window:

User Access Setup

Continue reading “MDGP October 2019 Release Feature of the Day: User Access Enhancements”

Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator

ClassicPress PluginsThis post is part of the sub-series on Internationalizing a ClassicPress plugin which is part of the Internationalizing a ClassicPress plugin series.

The esc_html_x function is very similar to the esc_html__ one, but has the addition of a comment section where context for the translator can be supplied. This is sometimes beneficial to use as the English language has words and phrases which can have different meanings dependent on context.

For example, the word minute:

$str = esc_html_x('Minute', 'measure of time', 'plugin-text-domain');
$str = esc_html_x('Minute', 'extremely small', 'plugin-text-domain');

Translating a ClassicPress plugin

Translating a ClassicPress plugin
What is Internationalization and Localization?
Why is Internationalization and Localization important?
When should a plugin be internationalized?
Internationalizing a ClassicPress plugin: How does internationalization work?
Internationalizing a ClassicPress plugin: What is a Text Domain and how is it specified?
Internationalizing a ClassicPress plugin: Localization functions
Internationalizing a ClassicPress plugin: Which localization functions to use?
Internationalizing a ClassicPress plugin: Localizing a string
Internationalizing a ClassicPress plugin: Don't paramaterize your text domain
Internationalizing a ClassicPress plugin: Localizing a string containing a parameter
Internationalizing a ClassicPress plugin: Localizing a string including plurals
Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator
Internationalizing a ClassicPress plugin: Don't include HTML markup in localization
Internationalizing a ClassicPress plugin: Don't localize URLs
Internationalizing a ClassicPress plugin: Localizing a string including line breaks
Internationalizing a ClassicPress plugin: Load plugin translations
Translating a ClassicPress plugin with Poedit: What is Poedit?
Translating a ClassicPress plugin with Poedit: Download Poedit
Translating a ClassicPress plugin with Poedit: Install Poedit
Translating a ClassicPress plugin with Poedit: Create New Translation Template
Translating a ClassicPress plugin with Poedit: Create Translations
Translating a ClassicPress plugin with GlotPress: What is GlotPress?
Translating a ClassicPress plugin with GlotPress: Download and install GlotPress
Translating a ClassicPress plugin with GlotPress: Creating administrators
Translating a ClassicPress plugin with GlotPress: Create a project
Translating a ClassicPress plugin with GlotPress: Import translation template
Translating a ClassicPress plugin with GlotPress: Import translations
Translating a ClassicPress plugin with GlotPress: Create new translation set
Translating a ClassicPress plugin with GlotPress: Export translations
Internationalizing a ClassicPress plugin
How does internationalization work?
What is a Text Domain and how is it specified?
Localization functions
Which localization functions to use?
Localizing a string
Don't paramaterize your text domain
Localizing a string containing a parameter
Localizing a string including plurals
Localizing a string including notes for the translator
Don't include HTML markup in localization
Don't localize URLs
Localizing a string including line breaks
Load plugin translations

MDGP October 2019 Release Feature of the Day: Export and Import Workflows

Microsoft Dynamics GPThe Inside Microsoft Dynamics GP blog has started a series Feature of the Day posts for Microsoft Dynamics GP “October 2019” Release on which I am following and adding commentary. The index for this series of posts is here.

The fourth Feature of the Day is Export and Import Workflows.

Have you setup a workflow in one company and want to create it in another company? A new workflow feature in Dynamics GP is the ability to Export and Import Workflows. If you export a workflow, a json file will be created with the format of the workflow.:

Workflow Maintenance export of workflow

Continue reading “MDGP October 2019 Release Feature of the Day: Export and Import Workflows”

Internationalizing a ClassicPress plugin: Localizing a string including plurals

ClassicPress PluginsThis post is part of the sub-series on Internationalizing a ClassicPress plugin which is part of the Internationalizing a ClassicPress plugin series.

As well as translating strings, and strings with parameters, you can also translate strings which include plurals. For example, you might have a counts of comments which would vary between 1 comment and 2 comments. This can be handled using the _n function.

There is no equivalent of esc_html__ for the plurals function, so you will need to wrap the _n function call with esc_html__ or esc_html_e:

esc_html_e(sprintf(
    _n(
        '%s comment',
        '%s comments',
        get_comments_number(),
        'plugin-text-domain'
    ),
    number_format_i18n(get_comments_number())
)
);

The _n() function accepts four arguments:

  1. single — the text to be used if the number is singular..
  2. plural — the text to be used if the number is plural.
  3. count — number to compare against to use either the singular or plural form.
  4. text domain — the plugin text domain.

The function returns the correct translated string for the supplied count.

Translating a ClassicPress plugin

Translating a ClassicPress plugin
What is Internationalization and Localization?
Why is Internationalization and Localization important?
When should a plugin be internationalized?
Internationalizing a ClassicPress plugin: How does internationalization work?
Internationalizing a ClassicPress plugin: What is a Text Domain and how is it specified?
Internationalizing a ClassicPress plugin: Localization functions
Internationalizing a ClassicPress plugin: Which localization functions to use?
Internationalizing a ClassicPress plugin: Localizing a string
Internationalizing a ClassicPress plugin: Don't paramaterize your text domain
Internationalizing a ClassicPress plugin: Localizing a string containing a parameter
Internationalizing a ClassicPress plugin: Localizing a string including plurals
Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator
Internationalizing a ClassicPress plugin: Don't include HTML markup in localization
Internationalizing a ClassicPress plugin: Don't localize URLs
Internationalizing a ClassicPress plugin: Localizing a string including line breaks
Internationalizing a ClassicPress plugin: Load plugin translations
Translating a ClassicPress plugin with Poedit: What is Poedit?
Translating a ClassicPress plugin with Poedit: Download Poedit
Translating a ClassicPress plugin with Poedit: Install Poedit
Translating a ClassicPress plugin with Poedit: Create New Translation Template
Translating a ClassicPress plugin with Poedit: Create Translations
Translating a ClassicPress plugin with GlotPress: What is GlotPress?
Translating a ClassicPress plugin with GlotPress: Download and install GlotPress
Translating a ClassicPress plugin with GlotPress: Creating administrators
Translating a ClassicPress plugin with GlotPress: Create a project
Translating a ClassicPress plugin with GlotPress: Import translation template
Translating a ClassicPress plugin with GlotPress: Import translations
Translating a ClassicPress plugin with GlotPress: Create new translation set
Translating a ClassicPress plugin with GlotPress: Export translations
Internationalizing a ClassicPress plugin
How does internationalization work?
What is a Text Domain and how is it specified?
Localization functions
Which localization functions to use?
Localizing a string
Don't paramaterize your text domain
Localizing a string containing a parameter
Localizing a string including plurals
Localizing a string including notes for the translator
Don't include HTML markup in localization
Don't localize URLs
Localizing a string including line breaks
Load plugin translations

Internationalizing a ClassicPress plugin: Localizing a string containing a parameter

ClassicPress PluginsThis post is part of the sub-series on Internationalizing a ClassicPress plugin which is part of the Internationalizing a ClassicPress plugin series.

If you have a string containing a parameter, say for example someone making a statement about the number of lights, you can combine your esc_html__ function with sprintf to switch out a placeholder with the number in a variable:

$str = sprintf(esc_html__('There are %d lights.', 'plugin-text-domain'), $number);

The %d will be contained in the string which can be translated; this is necessary as some languages may place the number in a different place of the sentence if it has a different sentence structure.

Translating a ClassicPress plugin

Translating a ClassicPress plugin
What is Internationalization and Localization?
Why is Internationalization and Localization important?
When should a plugin be internationalized?
Internationalizing a ClassicPress plugin: How does internationalization work?
Internationalizing a ClassicPress plugin: What is a Text Domain and how is it specified?
Internationalizing a ClassicPress plugin: Localization functions
Internationalizing a ClassicPress plugin: Which localization functions to use?
Internationalizing a ClassicPress plugin: Localizing a string
Internationalizing a ClassicPress plugin: Don't paramaterize your text domain
Internationalizing a ClassicPress plugin: Localizing a string containing a parameter
Internationalizing a ClassicPress plugin: Localizing a string including plurals
Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator
Internationalizing a ClassicPress plugin: Don't include HTML markup in localization
Internationalizing a ClassicPress plugin: Don't localize URLs
Internationalizing a ClassicPress plugin: Localizing a string including line breaks
Internationalizing a ClassicPress plugin: Load plugin translations
Translating a ClassicPress plugin with Poedit: What is Poedit?
Translating a ClassicPress plugin with Poedit: Download Poedit
Translating a ClassicPress plugin with Poedit: Install Poedit
Translating a ClassicPress plugin with Poedit: Create New Translation Template
Translating a ClassicPress plugin with Poedit: Create Translations
Translating a ClassicPress plugin with GlotPress: What is GlotPress?
Translating a ClassicPress plugin with GlotPress: Download and install GlotPress
Translating a ClassicPress plugin with GlotPress: Creating administrators
Translating a ClassicPress plugin with GlotPress: Create a project
Translating a ClassicPress plugin with GlotPress: Import translation template
Translating a ClassicPress plugin with GlotPress: Import translations
Translating a ClassicPress plugin with GlotPress: Create new translation set
Translating a ClassicPress plugin with GlotPress: Export translations
Internationalizing a ClassicPress plugin
How does internationalization work?
What is a Text Domain and how is it specified?
Localization functions
Which localization functions to use?
Localizing a string
Don't paramaterize your text domain
Localizing a string containing a parameter
Localizing a string including plurals
Localizing a string including notes for the translator
Don't include HTML markup in localization
Don't localize URLs
Localizing a string including line breaks
Load plugin translations

Internationalizing a ClassicPress plugin: Don’t paramaterize your text domain

ClassicPress PluginsThis post is part of the sub-series on Internationalizing a ClassicPress plugin which is part of the Internationalizing a ClassicPress plugin series.

A plugin can have a lot of strings to translate; the larger the plugin the more translations there are likely to be. It is quite common for developers to look for ways to reduce typing the same parameter every time through the use of variables or constants, but this must be resisted when it comes to setting the text domain parameter of the localization functions.

The reason for this is that it is not just the PHP of the plugin which needs to parse the translatable strings, but also the gettext libraries which are used to produce the POT templates, used by translators.

gettext is not a PHP parser, so it is unable to read variables or constants; it can only read the strings.

Translating a ClassicPress plugin

Translating a ClassicPress plugin
What is Internationalization and Localization?
Why is Internationalization and Localization important?
When should a plugin be internationalized?
Internationalizing a ClassicPress plugin: How does internationalization work?
Internationalizing a ClassicPress plugin: What is a Text Domain and how is it specified?
Internationalizing a ClassicPress plugin: Localization functions
Internationalizing a ClassicPress plugin: Which localization functions to use?
Internationalizing a ClassicPress plugin: Localizing a string
Internationalizing a ClassicPress plugin: Don't paramaterize your text domain
Internationalizing a ClassicPress plugin: Localizing a string containing a parameter
Internationalizing a ClassicPress plugin: Localizing a string including plurals
Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator
Internationalizing a ClassicPress plugin: Don't include HTML markup in localization
Internationalizing a ClassicPress plugin: Don't localize URLs
Internationalizing a ClassicPress plugin: Localizing a string including line breaks
Internationalizing a ClassicPress plugin: Load plugin translations
Translating a ClassicPress plugin with Poedit: What is Poedit?
Translating a ClassicPress plugin with Poedit: Download Poedit
Translating a ClassicPress plugin with Poedit: Install Poedit
Translating a ClassicPress plugin with Poedit: Create New Translation Template
Translating a ClassicPress plugin with Poedit: Create Translations
Translating a ClassicPress plugin with GlotPress: What is GlotPress?
Translating a ClassicPress plugin with GlotPress: Download and install GlotPress
Translating a ClassicPress plugin with GlotPress: Creating administrators
Translating a ClassicPress plugin with GlotPress: Create a project
Translating a ClassicPress plugin with GlotPress: Import translation template
Translating a ClassicPress plugin with GlotPress: Import translations
Translating a ClassicPress plugin with GlotPress: Create new translation set
Translating a ClassicPress plugin with GlotPress: Export translations
Internationalizing a ClassicPress plugin
How does internationalization work?
What is a Text Domain and how is it specified?
Localization functions
Which localization functions to use?
Localizing a string
Don't paramaterize your text domain
Localizing a string containing a parameter
Localizing a string including plurals
Localizing a string including notes for the translator
Don't include HTML markup in localization
Don't localize URLs
Localizing a string including line breaks
Load plugin translations

MDGP October 2019 Release Feature of the Day: Security Role and Task Workflows

Microsoft Dynamics GPThe Inside Microsoft Dynamics GP blog has started a series Feature of the Day posts for Microsoft Dynamics GP “October 2019” Release on which I am following and adding commentary. The index for this series of posts is here.

The third Feature of the Day is new workflows for Security Role and Task approval.

The last two new workflows are Security Task Approval and Security Roles Approval:

  1. Security Task Approval lets you edit the operations that are assigned to a task or create a new task; and if the workflow is active, the workflow actions will display on Security Task Setup.
  2. Security Roles Approval lets you edit the operations that are assigned to a role or create a new role; and if the workflow is active, the workflow actions will display on Security Role Setup.

With these Security Approval workflows, you can require that any changes made in these windows be submitted for review and approval:

Security Role Setup window

No changes made for Security Tasks or Security Roles will be implemented until the workflow task has been final approved.

I’ve fielded lots of questions over the years from clients asking how they can find out who has changed a role or task. These workflows will allow them to control changes with only a limited number of users able to approve a change and make it live.

Internationalizing a ClassicPress plugin: Localizing a string

ClassicPress PluginsThis post is part of the sub-series on Internationalizing a ClassicPress plugin which is part of the Internationalizing a ClassicPress plugin series.

Over the previous posts I’ve discussed adding text domains and which functions are available to use, it’s time to look at a practical application.

To return a translated string we’d use the esc_html__ function with the string which can be localized as the first parameter and the text domain as the second:

$str = esc_html__('This is the string to translate', 'plugin-text-domain');

If we wanted to echo the translated string rather than return it, we’d use the esc_html_e function:

esc_html_e('This is the string to translate', 'plugin-text-domain');

Translating a ClassicPress plugin

Translating a ClassicPress plugin
What is Internationalization and Localization?
Why is Internationalization and Localization important?
When should a plugin be internationalized?
Internationalizing a ClassicPress plugin: How does internationalization work?
Internationalizing a ClassicPress plugin: What is a Text Domain and how is it specified?
Internationalizing a ClassicPress plugin: Localization functions
Internationalizing a ClassicPress plugin: Which localization functions to use?
Internationalizing a ClassicPress plugin: Localizing a string
Internationalizing a ClassicPress plugin: Don't paramaterize your text domain
Internationalizing a ClassicPress plugin: Localizing a string containing a parameter
Internationalizing a ClassicPress plugin: Localizing a string including plurals
Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator
Internationalizing a ClassicPress plugin: Don't include HTML markup in localization
Internationalizing a ClassicPress plugin: Don't localize URLs
Internationalizing a ClassicPress plugin: Localizing a string including line breaks
Internationalizing a ClassicPress plugin: Load plugin translations
Translating a ClassicPress plugin with Poedit: What is Poedit?
Translating a ClassicPress plugin with Poedit: Download Poedit
Translating a ClassicPress plugin with Poedit: Install Poedit
Translating a ClassicPress plugin with Poedit: Create New Translation Template
Translating a ClassicPress plugin with Poedit: Create Translations
Translating a ClassicPress plugin with GlotPress: What is GlotPress?
Translating a ClassicPress plugin with GlotPress: Download and install GlotPress
Translating a ClassicPress plugin with GlotPress: Creating administrators
Translating a ClassicPress plugin with GlotPress: Create a project
Translating a ClassicPress plugin with GlotPress: Import translation template
Translating a ClassicPress plugin with GlotPress: Import translations
Translating a ClassicPress plugin with GlotPress: Create new translation set
Translating a ClassicPress plugin with GlotPress: Export translations
Internationalizing a ClassicPress plugin
How does internationalization work?
What is a Text Domain and how is it specified?
Localization functions
Which localization functions to use?
Localizing a string
Don't paramaterize your text domain
Localizing a string containing a parameter
Localizing a string including plurals
Localizing a string including notes for the translator
Don't include HTML markup in localization
Don't localize URLs
Localizing a string including line breaks
Load plugin translations

MDGP October 2019 Release Feature of the Day: User Security Workflow

Microsoft Dynamics GPThe Inside Microsoft Dynamics GP blog has started a series Feature of the Day posts for Microsoft Dynamics GP “October 2019” Release on which I am following and adding commentary. The index for this series of posts is here.

The second Feature of the Day is another new User Security Workflow to complement the one covered in the previous post of this series.

In User Security, you can make changes to the access for a user, what security role they are assigned or what modified reports they can access. With User Security Approval workflow, you can require that these changes be submitted for review and approval. This workflow is available in Workflow Maintenance (Administration area page » Setup » Company » Workflow » Workflow Maintenance):

Workflow Maintenance window showing User Security approval workflow

Continue reading “MDGP October 2019 Release Feature of the Day: User Security Workflow”

Internationalizing a ClassicPress plugin: Which localization functions to use?

ClassicPress PluginsThis post is part of the sub-series on Internationalizing a ClassicPress plugin which is part of the Internationalizing a ClassicPress plugin series.

In the previous post, of this series, I explained what functions were available for use in internationalizing a plugin, but there is something you need to consider when deciding which one to use.

With security at the forefront, it is important to remember that you cannot trust translators as you do not know who the translator will be. As you don’t know them, you can’t be sure that they won’t add something malicious to the translated string. To protect against this, you need to treat the localized strings as you would any other untrusted input: by escaping them.

So instead of using the plugins at the top of the previous post, you should be using the ones at the bottom which escape the returned or echoed strings.

Translating a ClassicPress plugin

Translating a ClassicPress plugin
What is Internationalization and Localization?
Why is Internationalization and Localization important?
When should a plugin be internationalized?
Internationalizing a ClassicPress plugin: How does internationalization work?
Internationalizing a ClassicPress plugin: What is a Text Domain and how is it specified?
Internationalizing a ClassicPress plugin: Localization functions
Internationalizing a ClassicPress plugin: Which localization functions to use?
Internationalizing a ClassicPress plugin: Localizing a string
Internationalizing a ClassicPress plugin: Don't paramaterize your text domain
Internationalizing a ClassicPress plugin: Localizing a string containing a parameter
Internationalizing a ClassicPress plugin: Localizing a string including plurals
Internationalizing a ClassicPress plugin: Localizing a string including notes for the translator
Internationalizing a ClassicPress plugin: Don't include HTML markup in localization
Internationalizing a ClassicPress plugin: Don't localize URLs
Internationalizing a ClassicPress plugin: Localizing a string including line breaks
Internationalizing a ClassicPress plugin: Load plugin translations
Translating a ClassicPress plugin with Poedit: What is Poedit?
Translating a ClassicPress plugin with Poedit: Download Poedit
Translating a ClassicPress plugin with Poedit: Install Poedit
Translating a ClassicPress plugin with Poedit: Create New Translation Template
Translating a ClassicPress plugin with Poedit: Create Translations
Translating a ClassicPress plugin with GlotPress: What is GlotPress?
Translating a ClassicPress plugin with GlotPress: Download and install GlotPress
Translating a ClassicPress plugin with GlotPress: Creating administrators
Translating a ClassicPress plugin with GlotPress: Create a project
Translating a ClassicPress plugin with GlotPress: Import translation template
Translating a ClassicPress plugin with GlotPress: Import translations
Translating a ClassicPress plugin with GlotPress: Create new translation set
Translating a ClassicPress plugin with GlotPress: Export translations
Internationalizing a ClassicPress plugin
How does internationalization work?
What is a Text Domain and how is it specified?
Localization functions
Which localization functions to use?
Localizing a string
Don't paramaterize your text domain
Localizing a string containing a parameter
Localizing a string including plurals
Localizing a string including notes for the translator
Don't include HTML markup in localization
Don't localize URLs
Localizing a string including line breaks
Load plugin translations