aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lessons/Lesson_54/README.md319
-rw-r--r--Lessons/Lesson_54/Translations1.pngbin0 -> 5832 bytes
-rw-r--r--Lessons/Lesson_54/Translations2.pngbin0 -> 7735 bytes
-rw-r--r--Lessons/Lesson_54/Translations3.pngbin0 -> 6336 bytes
-rw-r--r--Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c134
-rw-r--r--Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf20
-rw-r--r--Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dec45
-rw-r--r--Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dsc77
-rw-r--r--Lessons/Lesson_54/translations4.pngbin0 -> 8754 bytes
-rw-r--r--README.md1
-rw-r--r--UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c134
-rw-r--r--UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf20
-rw-r--r--UefiLessonsPkg/UefiLessonsPkg.dsc1
13 files changed, 751 insertions, 0 deletions
diff --git a/Lessons/Lesson_54/README.md b/Lessons/Lesson_54/README.md
new file mode 100644
index 0000000..9a46155
--- /dev/null
+++ b/Lessons/Lesson_54/README.md
@@ -0,0 +1,319 @@
+In this lesson we would try to add UNI translations dynamically to the system.
+
+For example we have a `PlatformDxe` which has strings only for the English language https://github.com/tianocore/edk2/blob/master/OvmfPkg/PlatformDxe/Platform.uni:
+```
+#langdef en-US "English"
+
+#string STR_FORMSET_TITLE #language en-US "OVMF Platform Configuration"
+#string STR_FORMSET_HELP #language en-US "Change various OVMF platform settings."
+#string STR_MAIN_FORM_TITLE #language en-US "OVMF Settings"
+#string STR_RES_CUR #language en-US "Preferred Resolution at Next Boot"
+#string STR_RES_CUR_HELP #language en-US "The preferred resolution of the Graphics Console at next boot. It might be unset, or even invalid (hence ignored) wrt. the video RAM size."
+#string STR_RES_NEXT #language en-US "Change Preferred Resolution for Next Boot"
+#string STR_RES_NEXT_HELP #language en-US "You can specify a new preference for the Graphics Console here. The list is filtered against the video RAM size."
+#string STR_SAVE_EXIT #language en-US "Commit Changes and Exit"
+#string STR_DISCARD_EXIT #language en-US "Discard Changes and Exit"
+```
+
+This means that even if we change our language preference to French in the BIOS menu, these strings still would be printed in English. You can verify it.
+
+With a help of a `Select Language` option change language to `Francais`
+![Translations1](Translations1.png?raw=true "Translations1")
+Then look at the `Device Manager->OVMF Platform Configuration`:
+![Translations2](Translations2.png?raw=true "Translations2")
+
+As you remember one string package has translation strings only for one language. If HII element supports multiple languages it would have multiple STRING packages in its package list. As for the `PlatformDxe` it has only one string package in its package list:
+https://github.com/tianocore/edk2/blob/master/OvmfPkg/PlatformDxe/Platform.inf
+```
+PackageList[9]: GUID=D9DCC5DF-4007-435E-9098-8970935504B2; size=0x855
+ Package[0]: type=FORMS; size=0x1F6
+ Package[1]: type=STRINGS; size=0x62B
+ Package[2]: type=DEVICE_PATH; size=0x1C
+ Package[3]: type=END; size=0x4
+```
+
+First let's print all possible strings from the package list. We saw the UNI source, but it is better to check this, as some strings can be added dynamilly in the system.
+
+To print strings from the package list we need `EFI_HII_HANDLE` of the package list. For this we can utilize `ListPackageLists` function from the `EFI_HII_DATABASE_PROTOCOL`:
+
+```
+EFI_HII_DATABASE_PROTOCOL.ListPackageLists()
+
+Summary:
+Determines the handles that are currently active in the database.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_LIST_PACKS) (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN OUT UINTN *HandleBufferLength,
+ OUT EFI_HII_HANDLE *Handle
+ );
+
+Parameters:
+This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+PackageType Specifies the package type of the packages to list or EFI_HII_PACKAGE_TYPE_ALL
+ for all packages to be listed.
+PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then this is the pointer to the
+ GUID which must match the Guid field of EFI_HII_GUID_PACKAGE_HDR. Otherwise, it must be NULL.
+HandleBufferLength On input, a pointer to the length of the handle buffer. On output, the length of the
+ handle buffer that is required for the handles found.
+Handle An array of EFI_HII_HANDLE instances returned. Type EFI_HII_HANDLE is
+ defined in EFI_HII_DATABASE_PROTOCOL.NewPackageList() in the Packages section.
+
+Description:
+This function returns a list of the package handles of the specified type that are currently active in the
+database. The pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package handles to be listed
+```
+
+With this function we need to call it once with a `HandleBufferLength=0`, receive `EFI_BUFFER_TOO_SMALL` error, but get the value for the `HandleBufferLength`. Allocate necessary size and call this function again. Standard UEFI mechanics which is already tedious.
+
+To make things easier let's utilize `HiiGetHiiHandles` function from the `HiiLib`:
+
+```
+/**
+ Retrieves the array of all the HII Handles or the HII handles of a specific
+ package list GUID in the HII Database.
+ This array is terminated with a NULL HII Handle.
+ This function allocates the returned array using AllocatePool().
+ The caller is responsible for freeing the array with FreePool().
+ @param[in] PackageListGuid An optional parameter that is used to request
+ HII Handles associated with a specific
+ Package List GUID. If this parameter is NULL,
+ then all the HII Handles in the HII Database
+ are returned. If this parameter is not NULL,
+ then zero or more HII Handles associated with
+ PackageListGuid are returned.
+ @retval NULL No HII handles were found in the HII database
+ @retval NULL The array of HII Handles could not be retrieved
+ @retval Other A pointer to the NULL terminated array of HII Handles
+**/
+EFI_HII_HANDLE *
+EFIAPI
+HiiGetHiiHandles (
+ IN CONST EFI_GUID *PackageListGuid OPTIONAL
+ )
+```
+
+With it our application can be as simple as this:
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_GUID PackageGuid = {0xD9DCC5DF, 0x4007, 0x435E, {0x90, 0x98, 0x89, 0x70, 0x93, 0x55, 0x04, 0xB2 }};
+ EFI_HII_HANDLE* Handle = HiiGetHiiHandles(&PackageGuid);
+
+ for (UINTN i=0; i<0xFFFF; i++) {
+ EFI_STRING String = HiiGetString(*Handle, i, "en-US");
+ if (String != NULL) {
+ Print(L"ID=%d, %s\n", i, String);
+ }
+ FreePool(String);
+ }
+ return EFI_SUCCESS;
+}
+```
+Here you can see that to get strings we simply loop over all possible string tokens and call `HiiGetString` function.
+
+If you build and execute this application now, you would get this:
+```
+FS0:\> HIIAddLocalization.efi
+ID=1, English
+ID=2, OVMF Platform Configuration
+ID=3, Change various OVMF platform settings.
+ID=4, OVMF Settings
+ID=5, Preferred Resolution at Next Boot
+ID=6, The preferred resolution of the Graphics Console at next boot. It might be unset, or even invalid (hence ignored) wrt. the video RAM size.
+ID=7, Change Preferred Resolution for Next Boot
+ID=8, You can specify a new preference for the Graphics Console here. The list is filtered against the video RAM size.
+ID=9, Commit Changes and Exit
+ID=10, Discard Changes and Exit
+ID=11, 640x480
+ID=12, 800x480
+ID=13, 800x600
+ID=14, 832x624
+ID=15, 960x640
+ID=16, 1024x600
+ID=17, 1024x768
+ID=18, 1152x864
+ID=19, 1152x870
+ID=20, 1280x720
+ID=21, 1280x760
+ID=22, 1280x768
+ID=23, 1280x800
+ID=24, 1280x960
+ID=25, 1280x1024
+ID=26, 1360x768
+ID=27, 1366x768
+ID=28, 1400x1050
+ID=29, 1440x900
+ID=30, 1600x900
+ID=31, 1600x1200
+ID=32, 1680x1050
+ID=33, 1920x1080
+ID=34, 1920x1200
+ID=35, 1920x1440
+ID=36, 2000x2000
+ID=37, 2048x1536
+ID=38, 2048x2048
+ID=39, 2560x1440
+ID=40, 2560x1600
+```
+
+Let's create an array with translations to the French language:
+```
+ CHAR16* FrenchStrings[] = {
+ L"Configuration de la OVMF plateforme",
+ L"Modifier divers paramètres de la plateforme OVMF",
+ L"Paramètres OVMF",
+ L"Résolution préférée au prochain démarrage",
+ L"La résolution préférée de la console graphique au prochain démarrage. Il peut être non défini, ou même invalide (donc ignoré) wrt. la taille de la RAM vidéo.",
+ L"Modifier la résolution préférée pour le prochain démarrage",
+ L"Vous pouvez spécifier ici une nouvelle préférence pour la console graphique. La liste est filtrée en fonction de la taille de la RAM vidéo.",
+ L"Valider les modifications et quitter",
+ L"Annuler les changements et quitter",
+ L"640x480",
+ L"800x480",
+ L"800x600",
+ L"832x624",
+ L"960x640",
+ L"1024x600",
+ L"1024x768",
+ L"1152x864",
+ L"1152x870",
+ L"1280x720",
+ L"1280x760",
+ L"1280x768",
+ L"1280x800",
+ L"1280x960",
+ L"1280x1024",
+ L"1360x768",
+ L"1366x768",
+ L"1400x1050",
+ L"1440x900",
+ L"1600x900",
+ L"1600x1200",
+ L"1680x1050",
+ L"1920x1080",
+ L"1920x1200",
+ L"1920x1440",
+ L"2000x2000",
+ L"2048x1536",
+ L"2048x2048",
+ L"2560x1440",
+ L"2560x1600",
+ };
+```
+Now let's comment the strings print loop. Next we need to create a strings package and populate it to the HII database under the same Package List. Here we can use one trick. Instead of a manual string package creation we can call `gHiiString->NewString` function with the dummy `L""` string in the new language. If `en-US` string package has 40 strings, this would create `fr-FR` string package with only one string `L""` with an ID=41. And this package would be automatically added to the package list.
+
+After the `fr-FR` string package is present in the package list, we can simply call `gHiiString->SetString` function for all of the data strings:
+```
+ EFI_STATUS Status;
+ for (UINTN i=0; i<(sizeof(FrenchStrings)/sizeof(FrenchStrings[0])); i++) {
+ EFI_STRING_ID StringId;
+ if (i==0) {
+ Status = gHiiString->NewString(gHiiString, *Handle, &StringId, "fr-FR", L"French", L"", NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! NewString fail\n");
+ }
+ }
+ StringId = i+2;
+ Status = gHiiString->SetString(gHiiString, *Handle, StringId, "fr-FR", FrenchStrings[i], NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! SetString fail for ID=%d\n", StringId);
+ }
+ }
+```
+
+Just in case here are the API description for the `NewString` and `SetString` functions from the `EFI_HII_STRING_PROTOCOL`:
+```
+EFI_HII_STRING_PROTOCOL.SetString()
+
+Summary:
+Change information about the string.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_SET_STRING) (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ );
+
+Parameters:
+This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+PackageList The package list containing the strings.
+Language Points to the language for the updated string.
+StringId The string id, which is unique within PackageList.
+String Points to the new null-terminated string.
+StringFontInfo Points to the string’s font information or NULL if the string font information is not changed.
+
+Description:
+This function updates the string specified by StringId in the specified PackageList to the text specified by
+String and, optionally, the font information specified by StringFontInfo
+```
+```
+EFI_HII_STRING_PROTOCOL.NewString()
+
+Summary:
+Creates a new string in a specific language and add it to strings from a specific package list.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_NEW_STRING) (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_STRING_ID *StringId
+ IN CONST CHAR8 *Language,
+ IN CONST CHAR16 *LanguageName OPTIONAL,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo
+ );
+
+Parameters:
+This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+PackageList Handle of the package list where this string will be added.
+Language Points to the language for the new string.
+LanguageName Points to the printable language name to associate with the passed in Language
+ field.
+String Points to the new null-terminated string.
+StringFontInfo Points to the new string’s font information or NULL if the string should have the
+ default system font, size and style.
+StringId On return, contains the new strings id, which is unique within PackageList.
+
+DescriptionL
+This function adds the string String to the group of strings owned by PackageList, with the specified font information StringFontInfo and returns a new string id
+```
+
+Don't forget to add `UefiHiiServicesLib` library class and its header `Library/UefiHiiServicesLib.h` for direct using of `gHiiString` protocol.
+
+Now build and run our application now.
+```
+FS0:\> HIIAddLocalization.efi
+FS0:\>
+```
+After that perform `exit` to go to the BIOS menu.
+
+Use `Select Language` option to change language to `Francais`. Then got to the `DeviceManager->OVMF Platform Configuration`. You can already see that translation are in place:
+![Translations4](Translations4.png?raw=true "Translations4")
+If you exit the menu and then go to it again you could even see that even the string in the `Device manager` is changed to "Configuration de la OVMF plateforme":
+![Translations3](Translations3.png?raw=true "Translations3")
+
diff --git a/Lessons/Lesson_54/Translations1.png b/Lessons/Lesson_54/Translations1.png
new file mode 100644
index 0000000..bd9be58
--- /dev/null
+++ b/Lessons/Lesson_54/Translations1.png
Binary files differ
diff --git a/Lessons/Lesson_54/Translations2.png b/Lessons/Lesson_54/Translations2.png
new file mode 100644
index 0000000..e7ca82a
--- /dev/null
+++ b/Lessons/Lesson_54/Translations2.png
Binary files differ
diff --git a/Lessons/Lesson_54/Translations3.png b/Lessons/Lesson_54/Translations3.png
new file mode 100644
index 0000000..1408442
--- /dev/null
+++ b/Lessons/Lesson_54/Translations3.png
Binary files differ
diff --git a/Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c b/Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c
new file mode 100644
index 0000000..27e525f
--- /dev/null
+++ b/Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c
@@ -0,0 +1,134 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/HiiLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_GUID PackageGuid = {0xD9DCC5DF, 0x4007, 0x435E, {0x90, 0x98, 0x89, 0x70, 0x93, 0x55, 0x04, 0xB2 }};
+ EFI_HII_HANDLE* Handle = HiiGetHiiHandles(&PackageGuid);
+
+/* *** If you add this: ***
+ for (UINTN i=0; i<0xFFFF; i++) {
+ EFI_STRING String = HiiGetString(*Handle, i, "en-US");
+ if (String != NULL) {
+ Print(L"ID=%d, %s\n", i, String);
+ }
+ FreePool(String);
+ }
+*/
+/* *** You would get: ***
+FS0:\> HIIAddLocalization.efi
+en;fr;en-US;fr-FR
+LangLen = 17
+en;fr;en-US;fr-FR;ru-RU
+Error! Can't set PlatformLangCodes variable, status=Write Protected
+ID=1, English
+ID=2, OVMF Platform Configuration
+ID=3, Change various OVMF platform settings.
+ID=4, OVMF Settings
+ID=5, Preferred Resolution at Next Boot
+ID=6, The preferred resolution of the Graphics Console at next boot. It might be unset, or even invalid (hence ignored) wrt. the video RAM size.
+ID=7, Change Preferred Resolution for Next Boot
+ID=8, You can specify a new preference for the Graphics Console here. The list is filtered against the video RAM size.
+ID=9, Commit Changes and Exit
+ID=10, Discard Changes and Exit
+ID=11, 640x480
+ID=12, 800x480
+ID=13, 800x600
+ID=14, 832x624
+ID=15, 960x640
+ID=16, 1024x600
+ID=17, 1024x768
+ID=18, 1152x864
+ID=19, 1152x870
+ID=20, 1280x720
+ID=21, 1280x760
+ID=22, 1280x768
+ID=23, 1280x800
+ID=24, 1280x960
+ID=25, 1280x1024
+ID=26, 1360x768
+ID=27, 1366x768
+ID=28, 1400x1050
+ID=29, 1440x900
+ID=30, 1600x900
+ID=31, 1600x1200
+ID=32, 1680x1050
+ID=33, 1920x1080
+ID=34, 1920x1200
+ID=35, 1920x1440
+ID=36, 2000x2000
+ID=37, 2048x1536
+ID=38, 2048x2048
+ID=39, 2560x1440
+ID=40, 2560x1600
+*/
+
+ CHAR16* FrenchStrings[] = {
+ L"Configuration de la OVMF plateforme",
+ L"Modifier divers paramètres de la plateforme OVMF",
+ L"Paramètres OVMF",
+ L"Résolution préférée au prochain démarrage",
+ L"La résolution préférée de la console graphique au prochain démarrage. Il peut être non défini, ou même invalide (donc ignoré) wrt. la taille de la RAM vidéo.",
+ L"Modifier la résolution préférée pour le prochain démarrage",
+ L"Vous pouvez spécifier ici une nouvelle préférence pour la console graphique. La liste est filtrée en fonction de la taille de la RAM vidéo.",
+ L"Valider les modifications et quitter",
+ L"Annuler les changements et quitter",
+ L"640x480",
+ L"800x480",
+ L"800x600",
+ L"832x624",
+ L"960x640",
+ L"1024x600",
+ L"1024x768",
+ L"1152x864",
+ L"1152x870",
+ L"1280x720",
+ L"1280x760",
+ L"1280x768",
+ L"1280x800",
+ L"1280x960",
+ L"1280x1024",
+ L"1360x768",
+ L"1366x768",
+ L"1400x1050",
+ L"1440x900",
+ L"1600x900",
+ L"1600x1200",
+ L"1680x1050",
+ L"1920x1080",
+ L"1920x1200",
+ L"1920x1440",
+ L"2000x2000",
+ L"2048x1536",
+ L"2048x2048",
+ L"2560x1440",
+ L"2560x1600",
+ };
+
+ EFI_STATUS Status;
+ for (UINTN i=0; i<(sizeof(FrenchStrings)/sizeof(FrenchStrings[0])); i++) {
+ EFI_STRING_ID StringId;
+ if (i==0) {
+ Status = gHiiString->NewString(gHiiString, *Handle, &StringId, "fr-FR", L"French", L"", NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! NewString fail\n");
+ }
+ }
+ StringId = i+2;
+ Status = gHiiString->SetString(gHiiString, *Handle, StringId, "fr-FR", FrenchStrings[i], NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! SetString fail for ID=%d\n", StringId);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf b/Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf
new file mode 100644
index 0000000..2d5a4f6
--- /dev/null
+++ b/Lessons/Lesson_54/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf
@@ -0,0 +1,20 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HIIAddLocalization
+ FILE_GUID = 1d20e66e-4b7e-4cbb-a8f5-a6e427aee1de
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ HIIAddLocalization.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ HiiLib
+ UefiHiiServicesLib
diff --git a/Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..40b351c
--- /dev/null
+++ b/Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com>
+#
+# SPDX-License-Identifier: MIT
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+ Include
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+ gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
+ gHIIStringsCGuid = { 0x8e0b8ed3, 0x14f7, 0x499d, { 0xa2, 0x24, 0xae, 0xe8, 0x9d, 0xc9, 0x7f, 0xa3 }}
+ gHIIStringsUNIGuid = { 0x6ee19058, 0x0fe2, 0x44ed, { 0x89, 0x1c, 0xa5, 0xd7, 0xe1, 0x08, 0xee, 0x1a }}
+ gHIIStringsUNIRCGuid = { 0x785693b4, 0x623e, 0x40fa, { 0x9a, 0x45, 0x68, 0xda, 0x38, 0x30, 0x89, 0xdd }}
+ gHIIAddRussianFontGuid = { 0x9fe2f616, 0x323c, 0x45a7, { 0x87, 0xa2, 0xdf, 0xef, 0xf5, 0x17, 0xcc, 0x66 }}
+
+[Protocols]
+ gSimpleClassProtocolGuid = { 0xb5510eea, 0x6f11, 0x4e4b, { 0xad, 0x0f, 0x35, 0xce, 0x17, 0xbd, 0x7a, 0x67 }}
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|42|UINT32|0x00000002
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|42|UINT32|0x00000003
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVarBool|FALSE|BOOLEAN|0x00000004
+
+[PcdsPatchableInModule]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32|0x31313131|UINT32|0x10000001
+
+[PcdsFeatureFlag]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar|FALSE|BOOLEAN|0x20000001
+
+[PcdsDynamic]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32|0x38323232|UINT32|0x30000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32_1|42|UINT32|0x30000002
+
+[PcdsDynamicEx]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicExVar32|0x38333333|UINT32|0x40000001
diff --git a/Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..48b78ca
--- /dev/null
+++ b/Lessons/Lesson_54/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,77 @@
+##
+# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com>
+#
+# SPDX-License-Identifier: MIT
+##
+
+[Defines]
+ DSC_SPECIFICATION = 0x0001001C
+ PLATFORM_GUID = 3db7270f-ffac-4139-90a4-0ae68f3f8167
+ PLATFORM_VERSION = 0.01
+ PLATFORM_NAME = UefiLessonsPkg
+ SKUID_IDENTIFIER = DEFAULT
+ SUPPORTED_ARCHITECTURES = X64
+ BUILD_TARGETS = RELEASE
+
+
+[LibraryClasses]
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ #PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ #SimpleLibrary|UefiLessonsPkg/Library/SimpleLibrary/SimpleLibrary.inf
+ #SimpleLibrary|UefiLessonsPkg/Library/SimpleLibraryWithConstructor/SimpleLibraryWithConstructor.inf
+ SimpleLibrary|UefiLessonsPkg/Library/SimpleLibraryWithConstructorAndDestructor/SimpleLibraryWithConstructorAndDestructor.inf
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+ UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
+ UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
+ UefiLessonsPkg/ListVariables/ListVariables.inf
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+ UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
+ UefiLessonsPkg/PCDLesson/PCDLesson.inf
+ UefiLessonsPkg/SmbiosInfo/SmbiosInfo.inf
+ UefiLessonsPkg/ShowTables/ShowTables.inf
+ UefiLessonsPkg/AcpiInfo/AcpiInfo.inf
+ UefiLessonsPkg/SaveBGRT/SaveBGRT.inf
+ UefiLessonsPkg/ListPCI/ListPCI.inf
+ UefiLessonsPkg/SimpleDriver/SimpleDriver.inf
+ UefiLessonsPkg/PCIRomInfo/PCIRomInfo.inf
+ UefiLessonsPkg/Library/SimpleLibrary/SimpleLibrary.inf
+ UefiLessonsPkg/Library/SimpleLibraryWithConstructor/SimpleLibraryWithConstructor.inf
+ UefiLessonsPkg/SimpleLibraryUser/SimpleLibraryUser.inf
+ UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf
+ UefiLessonsPkg/SimpleClassUser/SimpleClassUser.inf
+ UefiLessonsPkg/HotKeyDriver/HotKeyDriver.inf
+ UefiLessonsPkg/ShowHII/ShowHII.inf
+ UefiLessonsPkg/HIIStringsC/HIIStringsC.inf
+ UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
+ UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf
+ UefiLessonsPkg/HIIStringsMan/HIIStringsMan.inf
+ UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
+ UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44
+
diff --git a/Lessons/Lesson_54/translations4.png b/Lessons/Lesson_54/translations4.png
new file mode 100644
index 0000000..401cdfe
--- /dev/null
+++ b/Lessons/Lesson_54/translations4.png
Binary files differ
diff --git a/README.md b/README.md
index e995096..1ca24c0 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,7 @@ These series of lessons are intendend to get you started with UEFI programming i
- [Lesson 51](Lessons/Lesson_51): Add manual to UEFI application. How `-?` and `help` work in shell. `EFI_SHELL_GET_HELP_TEXT` function from the `EFI_SHELL_PROTOCOL`
- [Lesson 52](Lessons/Lesson_52): Add Russian font - Part 1: investigate `EFI_NARROW_GLYPH`/`EFI_WIDE_GLYPH` format, construct glyph array from the *.woff font file
- [Lesson 53](Lessons/Lesson_53): Add Russian font - Part 2: construct `EFI_HII_SIMPLE_FONT_PACKAGE` and populate it to the HII database
+- [Lesson 54](Lessons/Lesson_54): Use `NewString` and `SetString` functions from the `EFI_HII_STRING_PROTOCOL` to add String Package in a new language dynamically
_____
diff --git a/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c b/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c
new file mode 100644
index 0000000..27e525f
--- /dev/null
+++ b/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.c
@@ -0,0 +1,134 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/HiiLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_GUID PackageGuid = {0xD9DCC5DF, 0x4007, 0x435E, {0x90, 0x98, 0x89, 0x70, 0x93, 0x55, 0x04, 0xB2 }};
+ EFI_HII_HANDLE* Handle = HiiGetHiiHandles(&PackageGuid);
+
+/* *** If you add this: ***
+ for (UINTN i=0; i<0xFFFF; i++) {
+ EFI_STRING String = HiiGetString(*Handle, i, "en-US");
+ if (String != NULL) {
+ Print(L"ID=%d, %s\n", i, String);
+ }
+ FreePool(String);
+ }
+*/
+/* *** You would get: ***
+FS0:\> HIIAddLocalization.efi
+en;fr;en-US;fr-FR
+LangLen = 17
+en;fr;en-US;fr-FR;ru-RU
+Error! Can't set PlatformLangCodes variable, status=Write Protected
+ID=1, English
+ID=2, OVMF Platform Configuration
+ID=3, Change various OVMF platform settings.
+ID=4, OVMF Settings
+ID=5, Preferred Resolution at Next Boot
+ID=6, The preferred resolution of the Graphics Console at next boot. It might be unset, or even invalid (hence ignored) wrt. the video RAM size.
+ID=7, Change Preferred Resolution for Next Boot
+ID=8, You can specify a new preference for the Graphics Console here. The list is filtered against the video RAM size.
+ID=9, Commit Changes and Exit
+ID=10, Discard Changes and Exit
+ID=11, 640x480
+ID=12, 800x480
+ID=13, 800x600
+ID=14, 832x624
+ID=15, 960x640
+ID=16, 1024x600
+ID=17, 1024x768
+ID=18, 1152x864
+ID=19, 1152x870
+ID=20, 1280x720
+ID=21, 1280x760
+ID=22, 1280x768
+ID=23, 1280x800
+ID=24, 1280x960
+ID=25, 1280x1024
+ID=26, 1360x768
+ID=27, 1366x768
+ID=28, 1400x1050
+ID=29, 1440x900
+ID=30, 1600x900
+ID=31, 1600x1200
+ID=32, 1680x1050
+ID=33, 1920x1080
+ID=34, 1920x1200
+ID=35, 1920x1440
+ID=36, 2000x2000
+ID=37, 2048x1536
+ID=38, 2048x2048
+ID=39, 2560x1440
+ID=40, 2560x1600
+*/
+
+ CHAR16* FrenchStrings[] = {
+ L"Configuration de la OVMF plateforme",
+ L"Modifier divers paramètres de la plateforme OVMF",
+ L"Paramètres OVMF",
+ L"Résolution préférée au prochain démarrage",
+ L"La résolution préférée de la console graphique au prochain démarrage. Il peut être non défini, ou même invalide (donc ignoré) wrt. la taille de la RAM vidéo.",
+ L"Modifier la résolution préférée pour le prochain démarrage",
+ L"Vous pouvez spécifier ici une nouvelle préférence pour la console graphique. La liste est filtrée en fonction de la taille de la RAM vidéo.",
+ L"Valider les modifications et quitter",
+ L"Annuler les changements et quitter",
+ L"640x480",
+ L"800x480",
+ L"800x600",
+ L"832x624",
+ L"960x640",
+ L"1024x600",
+ L"1024x768",
+ L"1152x864",
+ L"1152x870",
+ L"1280x720",
+ L"1280x760",
+ L"1280x768",
+ L"1280x800",
+ L"1280x960",
+ L"1280x1024",
+ L"1360x768",
+ L"1366x768",
+ L"1400x1050",
+ L"1440x900",
+ L"1600x900",
+ L"1600x1200",
+ L"1680x1050",
+ L"1920x1080",
+ L"1920x1200",
+ L"1920x1440",
+ L"2000x2000",
+ L"2048x1536",
+ L"2048x2048",
+ L"2560x1440",
+ L"2560x1600",
+ };
+
+ EFI_STATUS Status;
+ for (UINTN i=0; i<(sizeof(FrenchStrings)/sizeof(FrenchStrings[0])); i++) {
+ EFI_STRING_ID StringId;
+ if (i==0) {
+ Status = gHiiString->NewString(gHiiString, *Handle, &StringId, "fr-FR", L"French", L"", NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! NewString fail\n");
+ }
+ }
+ StringId = i+2;
+ Status = gHiiString->SetString(gHiiString, *Handle, StringId, "fr-FR", FrenchStrings[i], NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! SetString fail for ID=%d\n", StringId);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf b/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf
new file mode 100644
index 0000000..2d5a4f6
--- /dev/null
+++ b/UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf
@@ -0,0 +1,20 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HIIAddLocalization
+ FILE_GUID = 1d20e66e-4b7e-4cbb-a8f5-a6e427aee1de
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ HIIAddLocalization.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ HiiLib
+ UefiHiiServicesLib
diff --git a/UefiLessonsPkg/UefiLessonsPkg.dsc b/UefiLessonsPkg/UefiLessonsPkg.dsc
index 4ddf8ff..48b78ca 100644
--- a/UefiLessonsPkg/UefiLessonsPkg.dsc
+++ b/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -70,6 +70,7 @@
UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf
UefiLessonsPkg/HIIStringsMan/HIIStringsMan.inf
UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
+ UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf
[PcdsFixedAtBuild]
gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44