Microsoft Dynamics AX 2012 underwent a name change in what would have been version 7. The product has been split, in terms of licensing, into Microsoft Dynamics 365 Finance and Microsoft Dynamics 365 Supply Chain Management. This is a further evolution from the previous name of Microsoft Dynamics 365 for Finance and Operations.
Even though it appears to be a component of Microsoft Dynamics 365, it is a separate product, so we can't abbreviate the name to Dynamics 365. We will refer to the product as either its full name or the SCM abbreviation that is used by Microsoft internally. You may see references to Unified operations in some Microsoft documentation.
The concept here is to make it easy to stay current and to avoid having customers on many different versions (such as 7.1, 7.2, 7.3, 8.1, and 8.1.2), hence the name One-Version. The associated challenges are mitigated through strong extensibility features that should allow partners and Independent Software Vendors (ISVs) to write code that is much easier to maintain and should not be impacted by updates.
For some time, we have had the platform updates being deployed in this way, so this is just a further evolution that brings some great benefits.
There are many references to the platform and application that we come across. Let's explain the difference between them, as follows:
- Platform: This can be considered the core kernel. This contains X++ language features, communication with SQL Server, integration services, and so on.
- Application: This is what the users actually use.
ISVs can get very excited about platform updates as they often contain new extensibility features and improvements for the language. The impact on users can be performance improvements and the way the controls look and feel.
All development work is carried out in conjunction with Azure DevOps, which was previously named Visual Studio Team Services. The application life cycle largely depends on this association. A simplified flow of this process is as follows:
- A new task or bug is logged in Azure DevOps.
- This task is then added to a sprint and allocated to a developer.
- A new feature or fix for an existing feature is developed in Visual Studio and checked into Azure DevOps. Here, it is marked as resolving the task or bug.
- The build server will build the new feature and automatically run test projects. The physical build server is being removed, but this step will still be performed, just not by a dedicated server.
- The resulting build package will be uploaded to Life Cycle Services (LCS) as a deployable package in the Asset library. Again, this will be an automated step as the build pipelines evolve.
- The package can then be deployed to the Sandbox environment for testing.
- Once tested, the package can be deployed to the production/live environment.
Please see the following links for further reading on Microsoft Dynamics 365 for Finance and Supply Chain Management:
- Development and administration for Finance and Supply Chain Management can be found at https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/.
- An overview of Microsoft Dynamics 365 for Finance and Supply Chain Management for Developers is available at https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/dev-tools/developer-home-page.
- To obtain an evaluation copy of Microsoft Dynamics 365 for Operations, please go to https://docs.microsoft.com/en-us/dynamics365/operations/dev-itpro/dev-tools/get-evaluation-copy.
All development work in SCM is either performed on a development Virtual Machine (VM) hosted in Azure or a local VM. Each developer will use their own VM. Azure-hosted VMs are deployed through LCS under your own Azure subscription and can be used for development, learning, and demonstration. When a customer buys a cloud-hosted subscription through their cloud service provider (partner), they are provided with two environments as part of that subscription, namely Sandbox and production. This is hosted on Microsoft's subscription and is managed by Microsoft as the service provider. The build server that was provided prior to the One-Version (or version 10) release is no longer required as there are new pipelines that can build, test, and deploy directly to LCS.
The Sandbox server is a full environment, with multiple servers using a separate Azure SQL Server. The production environment is the environment that you (as a customer) will go live with. All the code first be deployed to the Sandbox before it can go live, which is enforced by LCS – no more "quick fixes" directly into live and no access to SQL server for the production environment.
The on-premises version is still managed through LCS, and the development process is the same as it would be for the cloud version.
For local development, VMs are often the cheapest option, and we will download the VM from the LCS Asset library. This is a website that's used for many programs at Microsoft, and access is provided to partners and customers.
In this chapter, we will cover the following recipes:
- Creating the Azure DevOps project
- Connecting Visual Studio to Azure DevOps
- Creating a new package and model
- Configuring project and build options
- Creating a Label file
You can find the code files for this chapter on GitHub at https://github.com/PacktPublishing/Extending-Microsoft-Dynamics-365-Finance-and-Supply-Chain-Management-Cookbook-Second-Edition/blob/master/Chapter1.axpp.
The project is normally created under the end user's Azure DevOps site unless the work is being written as an ISV solution (or a personal development or learning project). The reason we use the client's Azure DevOps system is that LCS is associated with the Azure DevOps site, and support calls that are created through cloud-powered support are generated within the associated Azure DevOps. Cloud-powered support is an online support solution within LCS that is exposed to the SCM client, allowing users to log support issues with their internal support team.
Azure DevOps is free for up to five users, and the customer can create many accounts with limited access without charge. These accounts are called stakeholder accounts and allow the user to access work items. This account type also allows users to log support calls from within SCM. Accounts with an MSDN subscription do not consume free user accounts, which means that the free account total is only used by accounts that do not have an MSDN subscription.
This process is normally performed as part of LCS project creation. If this were an implementation project type, the project would be created when the customer signs up for SCM. The customer would then invite their cloud solution provider (referred to as their CSP or partner) to the project. If this were an internal development project, such as a new vertical solution by an ISV, a Migrate, create solutions, and learn Dynamics 365 for Operations project type would be used.
In either case, we will have an LCS project, which will usually have an Azure VM deployed that acts as a build server.
For simplicity, and to keep the focus on software development, a project of the Migrate, create solutions, and learn Dynamics 365 for Operations was created for the purposes of writing the code for this book.
Before we get started, we will need an LCS project and an Azure DevOps site. An Azure DevOps site can be created at https://www.visualstudio.com/en-us/products/visual-studio-team-services-vs.aspx.
Once we have created the site, we can create our project.
To create the project, follow these steps:
- Navigate to your Azure DevOps site; for example, https://<yourdomain>.visualstudio.com/.
- On the top right of the home page, click on Create project….
- Complete the form as shown as follow. Do not press Create:
|Project name||A unique name. Be careful to name the projects for easy recognition and how they are ordered. This is more important for ISVs who may have many projects.|
|Description||Short description of the project.
- Click Advanced and fill in the following two fields like so:
|Work item process||Agile|
|Version control||Team Foundation Version Control
- Press Create.
- Once complete, you can then navigate to your project and work with Azure DevOps in order to plan your project.
- To authenticate with LCS, we will need to generate a personal access token; from within Azure DevOps, click on your user's account name and select Security from the drop-down options.
- The personal access tokens option is selected by default; on the right-hand pane, click on New token.
- On the Create a personal access token form, enter a short description; for example, the LCS project's name. Set the Expires field based on how long you would like it to last for.
- Set the Scopes to Full access. Then, press Create token.
- Finally, copy the personal access code into a safe place; we will need it when we link Azure DevOps to LCS. If we don't, we will have to create a new access token as we won't be able to see it after this point.
Next, we will need to link the project to our LCS project. If an LCS project is not currently linked to an Azure DevOps project, we get the following message on the left-hand side:
To configure Azure DevOps for the LCS project, follow these steps:
- Click on the Setup Visual Studio Team Services button in the Action center dialog box.
- On the Enter the site page, enter the URL of our Azure DevOps site into the Azure DevOps site URL field; for example, https://<mysite>.visualstudio.com/.
- Enter the personal access token we generated earlier into the Personal access token field.
- Press Continue.
- On the Select the Visual Studio Team Service project page, select the project from the Visual Studio Team Service list.
- Press Continue.
- On the final Review and save page, press Save.
To complete the setup, we need to create some folders in the project's repository. To do this, follow these steps:
- Open your Azure DevOps site and select the project we created earlier.
- You will see a list on the left for each area of Azure DevOps. Select the Repos section and then click Files.
- On the right, you will see a folder named BuildProcessTemplates. We need a sibling folder called Trunk. Against the root node (this will be in the format of $/<ProjectName>), click the ellipses (…) and select New | Folder.
- In the Check-in dialog, enter Trunk and press Check-In.
- Click the ellipses icon (…) on the new Trunk folder, click New | Folder, and create a folder named Main. This will be the main development branch containing metadata (the actual source code) and projects.
- Click the ellipses on the new Main folder and create two sibling subfolders named Metadata and Projects. The final structure should be as follows:
The steps in this recipe resulted in a new folder structure that will contain code that is ready for deployment to the Sandbox and then production. Based on experience, in development, having a two-branch Application Lifecycle Management (ALM) strategy works best in most scenarios. The concept is that all development is to be done in Dev, and when the work passes testing, the Dev branch is merged into Main and Main is deployed to the Sandbox for final testing and then moved to production. Once the code has been moved to production, the Dev branch is reset from Main. We will create the Dev branch from within Visual Studio in the next recipe.
SCM uses Azure DevOps for its source control, work, and build management. The personal access token provides the security context in which LCS can interact with Azure DevOps. This means that when issues are logged by users, they will appear as issues in Azure DevOps. This is done using an area called LcsGeneratedIssues, which you can then use as a triage list in order to plan a resolution to the reported issue. These issues can then be submitted to Microsoft for support assistance directly from within LCS.
The structure of the repository is the way it is so that we can use branch management strategies that keep source code and project files together, even though they are stored in different locations on the development workstations.
For more information on Azure DevOps and LCS, please check out the following links:
- Lifecycle Services (LCS) for Finance and Supply Chain Management, at https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/lifecycle-services/lcs/.
- LCS for Microsoft Dynamics 365 for Operations customers, at https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/lifecycle-services/lcs-works-lcs/.
- For more information on LCS, please go to https://lcs.dynamics.com/Logon/Index.
- The following link doesn't quite match the current state of Azure DevOps but provides some great background information on version control, metadata search, and navigation, at https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/dev-tools/version-control-metadata-navigation.
- The following link contains some useful background knowledge, but a lot of this based on when using an implementation LCS project, at https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/lifecycle-services/cloud-powered-support-lcs/.
This link is for when we have a customer implementation project and we want to demonstrate some of the synergies of leveraging Azure DevOps and LCS with SCM.
Each developer has their own development virtual machine (VM), hosted either in Azure or locally. This is by design and is part of the application life cycle process. Connecting to Azure DevOps allows our code to be checked into source control and allows the team to work together on the same code base. Each developer would get the latest code from the source control and then check in their changes according to their organization's development methodology. As part of this check-in process, they can associate the check-ins to work items that were created in Azure DevOps (tasks, bugs, user stories), which allows us to easily determine what work is being deployed in a build. This process also allows test projects to be automatically executed when the build is generated.
We will be working with a two-branch strategy, which means starting with the Main branch and creating a Dev branch from that.
Once the VM has started, ensure that it has internet access and that you have used the admin user provisioning tool to associate your O365 account with the administrator account of SCM.
When working with multiple developers, one often overlooked task is renaming the VM. This has gotten easier with each update, and the steps we take at the current release are as follows:
- Use computer management to rename the machine. I use a project reference, version, and initials, such as CON-V10-PU24-SB.CON could be the reference to a vertical solution or the customer's initials if you're developing their specific requirements. CON (short for Contoso) in this case, which is a fictitious partner organization.
- Restart the VM.
- Use the SQL Server Reporting Services configuration utility so that it references the correct server name.
- When we are linking up the first workstation, we would use that to set up the branching strategy. This means creating two sets. We start with the Main branch, so create folders that match the following structures:
- Start Visual Studio.
- You will be presented with the licensing page. Use the page to log in to the account you used to create the project within Azure DevOps, which could be either your Microsoft account or Work (O365) account.
- On the top toolbar, select Team and then Manage Connections.
- The Team Explorer will open, under default layout, on the right-hand side. On this pane, select Manage Connections | Connect to Team Project:
- This will open the Connect to Team Foundation Server dialog. From the Select a Team Foundation Server drop-down list, select your Azure DevOps site.
- Select your project in the lower portion of the dialog, as shown in the following screenshot:
- After pressing Connect, Visual Studio will be connected to your project.
- We have one final step to complete before we continue; we have to configure our workspace so that Visual Studio knows which folders are under source control and how they map to Azure DevOps. On Team Explorer, click on Configure workspace under the Project section. This will show the Configure Workspace section at the top of the Team Explorer.
- Don't press Map & Get.
- Press Advanced....
- Alter the mappings so that you have two lines that follow the format shown in the following screenshot:
- Press OK.
- On the Workspace Modified dialog, press Yes to get the files from Azure DevOps.
- On the right-hand side, under the Team Explorer, click on the Source Control Explorer tile.
- You will see all the sites available to you in an explorer view. On the Source Control Explorer's left pane, expand your project. Do the same for the Trunk folder so that you can see the Main folder. Right-click on this folder, choose Branching and Merging | Convert to Branch…, and click Convert when the appropriate dialog is displayed.
- Next, we need to create our Dev branch. Right-click on the Main branch and choose Branching and Merging | Branch….
- In the Branch from the Main dialog, change the name from Main-branch to Dev. It must sit under $/<project name>/Trunk/.
- Finally, we need to change our mapping so that it links to the Dev branch. Click the home button on the Team Explorer pane on the right-hand side and click Manage Workspaces..., as shown in the following screenshot:
- Click Edit and rename all the references from Main to Dev, as shown in the following screenshot:
- Press OK, and then Yes.
Source control in SCM has come a long way in this release, mainly because our development tool is now Visual Studio and the source files are now actual files in the filesystem. SCM no longer needs special code to integrate with a Team Foundation Server.
The reason we have two folders is that our projects don't actually contain the files we create when writing code. When we create a file, such as a new class, it is created within the local packages folder and referenced within the project. This also means that we can't just zip up a project and email it to a co-worker. This is done by connecting to the same Azure DevOps project or using the project export feature.
The following links provide further relevant information for when we're setting up new VMs with Azure DevOps:
When creating a new project, we usually create a new package and a new model. This keeps things simple, and there is usually no benefit in separating them. You may wish to create a test project in a different model in the same solution, but you may not wish to deploy the test projects to live.
There are two types of projects:
- An extension project
- An over-layer project
Over-layering means modifying the source code of SCM and requires a code upgrade for each application hotfix. Extension projects work on delta changes to the standard object or use delegates to affect code execution. Extension projects are less likely to require a code upgrade when application hotfixes are applied. Avoiding over-layering cannot be overstated because, at the time of writing, all Microsoft supplier packages are locked. The ability to write good code through extension has been improved with each release, and now that over-layering is only available to ISV solutions, the development paradigm has had to shift significantly from the AX2012 development days.
In this recipe, we will use extension projects exclusively in order to avoid conflicts with future upgrades. They make it possible for us to service the environment without having to deploy a new build of the custom solution. This is very exciting for ISV solutions, but also very important for partners/Value-Added Resellers (VAR) and end-user customers.
See There's more... section for information on the relationship between packages, models, and projects.
Start Visual Studio and ensure that we are correctly connected to Azure DevOps. With the current release, you must start Visual Studio as an administrator.
- Under the Dynamics 365 menu, choose Model Management | Create model….
- The model name is named as it would be in AX 2012, and should be named like a new type, such as <prefix><ShortName>.
- Complete the first page as follows:
- Model name: In our case, our company is called Contoso, so our prefix will be Con, and we are writing a vehicle management solution. Therefore, we have named it ConVehicleManagement. You should use your own prefix and prefixes, as well as a unique name, which is explained further in the There's more... section.
- Model publisher: Your organization's name.
- Layer: ISV or vertical solution. Here, choose ISV. For partner projects choose VAR. Customers can use CUS or USR.
- Version: Leave as 18.104.22.168.
- Model description: A full description of the model for other developers to read.
- Model display name: This should be something like Contoso – vehicle management in our case.
- Press Next.
- On the Select package page, choose Create new package.
- Press Next.
- We are now offered a list of packages that we can reference, listed as package names and the models that each package contains. Leave ApplicationPlatform checked. Additionally, check ApplicationFoundation, ApplicationCommon, and ApplicationSuite and then press Next.
- The Create new project and Make this my default model for new projects checkboxes should both be checked.
- Press Finish.
- This opens the New Project dialog. The project name is usually the same as the package and model name. Now, enter the package name in the Name field.
- The Location field must be changed; it will be created in the default project folder. Here, we linked C:\Trunk\Dev to source control. The project must be created under this folder. So, in my case, Location must be C:\Trunk\Dev\Projects.
- The Solution name field should be left as the project name.
- Ensure that both Create directory for the solution and Add to source control are checked.
- Press OK.
To see what we just did, we can simply look at the results. Use Windows Explorer to navigate to the local packages folder, which is usually C:\AOSService\PackagesLocalDirectory. There, you will see the following structure for our example package, that is, ConVehicleManagement:
The root folder is the Package and contains a subfolder for the model, which has the same name. All of the code is under the model folder in a separate folder for each type. The descriptor folder contains an XML definition file. XppMetaData is a system-managed folder for the Xpp metadata for all the models in the package. This holds compiler metadata information about each element, not the actual source code. This includes the methods in a class, the type of method, and the parameters.
We would never normally change anything here, but there are exceptions:
- If two developers create a different package at the same time, they can both get the same model ID, in which case conflicts will occur when they check in. The solution is to check out the model's descriptor XML file in the Source Control Explorer and manually change the ID to the next number.
- You may decide that a standard package should be deleted, such as the tutorial or the sample fleet management solution. You can do this by simply deleting the package folder. Should you want to remove a standard model, you can delete the model folder, but you must also delete the relevant model descriptor file from the package's Descriptor folder. Obvious care needs to be taken, as you can't get it back!
The former point can be prevented by nominating a person to create packages and models.
If you look in the Source Control Explorer in Visual Studio, you will only see that the projects folder has been added. This is correct. The folders under the Metadata folder will only appear when we create new elements.
When a solution is designed, it will be done by breaking the solution into packages of functionality. This is a normal design paradigm that has now been implemented (and, to an extent, enforced) within SCM. This means that our solution design will now define the various packages and their dependencies. In the case of SCM, a Package is a deployable unit.
We can make a hotfix to a package and, technically, deploy it separately to other packages in the solution. Although this is possible, we would normally create a release of packages as a deployable package. A deployable package is a collection of one or more packages that contain both the built code and the routine required to install them. This process is simplified using a build server that performs the build process for us, executes any tests, and creates deployable packages that we can then apply to our test environment.
There is a further level within SCM, which is a model. A model is a subset of elements, such as classes, within a package and can be used to move code from one development system to another, for example. A model can only belong to one package, and a Package can contain one or more models. Each package becomes (effectively) a Dynamic Link Library (DLL), which has to have references added in order to see elements in order packages. Because of this, we should use a limited number of packages. As a guide, we tend to have one package for mainstream development. To simplify the management of development tasks, we tend to have a project per Specification/Technical Design Document (TDD), all within the main package, simplifying multi-developer projects. Just like working on complex C# projects, we can perform code merges, branching, and shelving within Azure DevOps. This means having a label file per project; otherwise, we will have a conflict each time we check in a change to the label file.
Layers have been a core part of prior releases from its first release but are no longer that significant. As a partner, we still use the VAR layer and recommend the same guidelines as before to customers, but since we avoid over-layering, this feature will not be covered in this book.
The following diagram shows a typical Package, Model, and Project structure:
The ApplicationSuite package is a standard package that we normally always reference as it contains the majority of the types that we usually need. The arrows in the preceding diagram indicate the reference direction, showing that it is not possible for the Vehicle management package to see the elements that were created in the Vehicle management reporting package.
SCM does not use namespaces. Neither packages nor models equate to a namespace. A model simply implies a scope, but all types must be globally unique, even in different models and packages. A namespace would allow a class to have the same name as another class in a different namespace.
Therefore, every element must be globally unique by type; this includes models, packages, and every element in the application metadata. So, we will still need prefixes. Even if we create an extension of an element, such as a form, we must change the name so that it is guaranteed to be globally unique.
For example, if we wanted to create an extension of the WHSLoadTable table, it will call the WHSLoadTable.extension object by default. As our customer might want an add-on that also adds fields to this table, we need to ensure that the element is unique.
The best way to do this would be to use our prefix, which is Con in our case. To make it obvious where the element is used, we use the package name as the suffix; for example, WHSLoadTable.ConVehicleManagement. There is no official best practice available for this, but remember that all the elements of a type must be globally unique – and extensions are no exception.
This naming also applies to extensions to classes and event handler classes. We always start with the type name being extended, followed by the project name and then the type of extension. The following examples show this in a project named ConVehicleManagement:
|Type||Reason||Type being extended||Example name of the extension type|
|Class||Delegate or pre-post||InventMovement||InventMovement_ConVehicleManagement_EventHandler|
|Form code||Code extension||CustTable||CustTable_ConVehicleManagement_FormHandler|
This is what works for us, as we can easily see all the areas that a standard type is augmented in or has events handled and know which project (and roughly the reason for the change) at a glance. The key here is to be consistent at all times.
Before we start developing code for the first time in a new VM, we should set up some parameters in Visual Studio. Many of the settings that are described here are good for all projects, but you may wish to change some, depending on the scenario. This recipe explains how to configure the required parameters.
This follows the previous recipe but can apply equally to any SCM project. Just load up Visual Studio and the project you wish to configure.
This recipe will be split into two parts, that is, Finance and Supply Chain Management are generic options for all projects and project-specific parameters.
Before we do either, we should always have the Application Explorer open, which is hidden by default. This is the Application Object Tree (AOT) of prior versions, and it can be opened from the View menu.
To configure the generic options for all projects, follow these steps:
- Select Options from the Dynamics 365 menu.
- The default option in the left-hand tree view is Debugging; the options here are usually fine. The Load symbols for items in this solution option affect debugging and should be left checked for the performance of the debugger. We would uncheck this if we wanted to trace code that calls code outside of the current package.
- Select the Projects option on the left and Organize projects by element type. When adding new elements to the project, it will automatically create a subfolder in the project for the element type. This makes the organization much easier to maintain.
- The other two options should be left blank. Although the Synchronize database on build for newly created projects option can be useful, this database synchronization takes time, and it is usually preferable to do this as required.
- The Best practices node lets you choose which best practice checks you wish to be executed on the build. This detail is beyond the scope of this book as the checks that are required are case-specific.
The project-specific parameters are usually fine as they are for development. Some changes are required when we want to debug using the sample data that comes with the VM. Primarily, it needs to know the entry point to debug and the company data that the session should start with.
To set up the common parameters, follow these steps:
- Right-click on 59 in the Solution Explorer and choose Properties.
- To save time while debugging, select which object you wish to start with. To start with the form SalesTable, set the Startup Object Type option to Form and Startup Object to SalesTable.
- Set Company to USMF or any other company you wish to start with when debugging.
- Leave Partition as initial. These are now only supported for certain unit test scenarios.
- If you wish to always synchronize the database on the build, you can set Synchronize Database on Build. My advice is to do this manually as required after the build completes.
Most projects have some kind of user interface, so we need to display text to the user, as well as the field names. The best practice way to do this is to use a label file. The label file contains a language-specific dictionary of label IDs and their translation.
Standard elements tend to have the legacy label IDs of an @ symbol, followed by a three-digit label ID and a number. This format has worked well for the past 15 years, but the prefix was potentially limiting, especially for aiding ISVs. Labels are no longer restricted to three digits, which helps Microsoft attain one of its goals of making ISV add-ons easier to write, maintain, and adopt.
The choice of how many and which packages need a label file depends on the solution design.
We tend to create a label file for each project as this ensures that the developer of the project can correct and change labels without worrying about regression in other projects in the same package.
To get started, open Visual Studio and the project in question. In my case, I will continue with the ConVehicleManagent project.
- Right-click on the project and select Add | New item… or use the Ctrl + Shift + A keyboard shortcut.
- Choose Labels and Resources from the Dynamics 365 items list.
- From the list on the left, select Label File.
- In the Name field, enter a short but unique label name. In my case, this is ConVMS. I want it to be as short as possible but still be completely sure it will be globally unique, regardless of any future add-on we may choose to install.
- Press Add.
- In the Label file wizard, leave the Label file ID as its default.
- Press Next.
- In the language selection, move the languages from the left-hand list into the right-hand list using the buttons. Only leave languages selected that you will maintain. This involves creating a label in each language file.
- Press Next.
- Check that the Summary page is correct and press Finish.
The creation process is straightforward. The process creates a text file on the disk that contains a tab-separated list of label IDs and the translation.
When a label is selected against a control, it will be given a label file ID that ensures it is unique. In our example, the label file ID was ConVMS. When we create a label, we will state the ID as a short identifier name as this makes the label easier to read in code and in property sheets. @ConVMS:L001 is not very memorable, but @ConVMS:ItemNotExists is far easier to understand.
This also applies to language with subtle differences, such as English and Spanish. Even though the label will often be the same, we still need to manually maintain each language file. Currently, this also means we have to be careful that we give them the correct ID.
Currently, the maintenance of labels can be time-consuming in that we don't have a translation list per label ID as we did in Dynamics AX 2012. Instead, we have a separate file per language. This has been done as an improvement and may change by release. The concept, however, will remain the same.
When writing labels for variants of the same or similar languages, we can copy and paste the labels between files. To do so, we can expand the label file to the lowest node to the file with a .txt extension, right-click on it to select Open With…, and choose Source Code (Text) Editor from the list.
Each label will have two lines – one for the label and another for the comment – as shown in the following extract from an en-gb label file:
VehicleTypeHT=The type of vehicle
VehTransCompleteHT=Complete, and finalise the vehicle inspection
You can then translate to the desired language and paste it into the target label file, again by opening the text file in the source code editor. You must do this from within Visual Studio (and not in a separate editor outside of Visual Studio); otherwise, the file may not be checked out from source control. Be careful when editing in this way as the source code editor will not validate that there aren't duplicates or file formatting errors.
If you intend to write add-ons, you should always maintain the en-us language file. You will get compilation warnings that the label ID does not exist if you do not. If you are to release the software to a region with a variant of a language (en-au, en-gb, en-ie, en-us, and so on), please use the correct translation. Not only will it make your add-on more professional and global, but some terms across even English-speaking countries have completely different meanings. For example, stock means inventory in en-gb, but means financial shareholdings in en-us.