diff --git a/.golangci.yml b/.golangci.yml
index a80fe164d7e..5bd0bfaaa3e 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -33,6 +33,51 @@ linters:
     #- protogetter
 
 linters-settings:
+  govet:
+    # Enable analyzers by name.
+    # Run `GL_DEBUG=govet golangci-lint run --enable=govet` to see default, all available analyzers, and enabled analyzers.
+    enable:
+      - appends
+      - asmdecl
+      - assign
+      - atomic
+      - atomicalign
+      - bools
+      - buildtag
+      - cgocall
+      - composites
+      - copylocks
+      - deepequalerrors
+      - defers
+      - directive
+      - errorsas
+      #- fieldalignment
+      - findcall
+      - framepointer
+      - httpresponse
+      - ifaceassert
+      - loopclosure
+      - lostcancel
+      - nilfunc
+      - nilness
+      - printf
+      - reflectvaluecompare
+      #- shadow
+      - shift
+      - sigchanyzer
+      - slog
+      - sortslice
+      - stdmethods
+      - stringintconv
+      - structtag
+      - testinggoroutine
+      - tests
+      - unmarshal
+      - unreachable
+      - unsafeptr
+      - unusedresult
+      - unusedwrite
+
   forbidigo:
     forbid:
       - p: ^(fmt\.Print(|f|ln)|print|println)$
diff --git a/commands/cmderrors/cmderrors.go b/commands/cmderrors/cmderrors.go
index a5024a37a26..bcc33bc3a8f 100644
--- a/commands/cmderrors/cmderrors.go
+++ b/commands/cmderrors/cmderrors.go
@@ -26,8 +26,6 @@ import (
 	"google.golang.org/grpc/status"
 )
 
-var tr = i18n.Tr
-
 func composeErrorMsg(msg string, cause error) string {
 	if cause == nil {
 		return msg
@@ -45,7 +43,7 @@ type CommandError interface {
 type InvalidInstanceError struct{}
 
 func (e *InvalidInstanceError) Error() string {
-	return tr("Invalid instance")
+	return i18n.Tr("Invalid instance")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -59,7 +57,7 @@ type InvalidFQBNError struct {
 }
 
 func (e *InvalidFQBNError) Error() string {
-	return composeErrorMsg(tr("Invalid FQBN"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Invalid FQBN"), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -77,7 +75,7 @@ type InvalidURLError struct {
 }
 
 func (e *InvalidURLError) Error() string {
-	return composeErrorMsg(tr("Invalid URL"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Invalid URL"), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -95,7 +93,7 @@ type InvalidLibraryError struct {
 }
 
 func (e *InvalidLibraryError) Error() string {
-	return composeErrorMsg(tr("Invalid library"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Invalid library"), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -113,7 +111,7 @@ type InvalidVersionError struct {
 }
 
 func (e *InvalidVersionError) Error() string {
-	return composeErrorMsg(tr("Invalid version"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Invalid version"), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -132,7 +130,7 @@ type NoBoardsDetectedError struct {
 }
 
 func (e *NoBoardsDetectedError) Error() string {
-	return tr(
+	return i18n.Tr(
 		"Please specify an FQBN. The board on port %[1]s with protocol %[2]s can't be identified",
 		e.Port.GetAddress(),
 		e.Port.GetProtocol(),
@@ -152,7 +150,7 @@ type MultipleBoardsDetectedError struct {
 }
 
 func (e *MultipleBoardsDetectedError) Error() string {
-	return tr(
+	return i18n.Tr(
 		"Please specify an FQBN. Multiple possible boards detected on port %[1]s with protocol %[2]s",
 		e.Port.GetAddress(),
 		e.Port.GetProtocol(),
@@ -168,7 +166,7 @@ func (e *MultipleBoardsDetectedError) GRPCStatus() *status.Status {
 type MissingFQBNError struct{}
 
 func (e *MissingFQBNError) Error() string {
-	return tr("Missing FQBN (Fully Qualified Board Name)")
+	return i18n.Tr("Missing FQBN (Fully Qualified Board Name)")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -182,7 +180,7 @@ type UnknownFQBNError struct {
 }
 
 func (e *UnknownFQBNError) Error() string {
-	return composeErrorMsg(tr("Unknown FQBN"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Unknown FQBN"), e.Cause)
 }
 
 func (e *UnknownFQBNError) Unwrap() error {
@@ -201,7 +199,7 @@ type UnknownProfileError struct {
 }
 
 func (e *UnknownProfileError) Error() string {
-	return composeErrorMsg(tr("Profile '%s' not found", e.Profile), e.Cause)
+	return composeErrorMsg(i18n.Tr("Profile '%s' not found", e.Profile), e.Cause)
 }
 
 func (e *UnknownProfileError) Unwrap() error {
@@ -219,7 +217,7 @@ type InvalidProfileError struct {
 }
 
 func (e *InvalidProfileError) Error() string {
-	return composeErrorMsg(tr("Invalid profile"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Invalid profile"), e.Cause)
 }
 
 func (e *InvalidProfileError) Unwrap() error {
@@ -235,7 +233,7 @@ func (e *InvalidProfileError) GRPCStatus() *status.Status {
 type MissingPortAddressError struct{}
 
 func (e *MissingPortAddressError) Error() string {
-	return tr("Missing port address")
+	return i18n.Tr("Missing port address")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -247,7 +245,7 @@ func (e *MissingPortAddressError) GRPCStatus() *status.Status {
 type MissingPortProtocolError struct{}
 
 func (e *MissingPortProtocolError) Error() string {
-	return tr("Missing port protocol")
+	return i18n.Tr("Missing port protocol")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -259,7 +257,7 @@ func (e *MissingPortProtocolError) GRPCStatus() *status.Status {
 type MissingPortError struct{}
 
 func (e *MissingPortError) Error() string {
-	return tr("Missing port")
+	return i18n.Tr("Missing port")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -273,7 +271,7 @@ type NoMonitorAvailableForProtocolError struct {
 }
 
 func (e *NoMonitorAvailableForProtocolError) Error() string {
-	return tr("No monitor available for the port protocol %s", e.Protocol)
+	return i18n.Tr("No monitor available for the port protocol %s", e.Protocol)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -285,7 +283,7 @@ func (e *NoMonitorAvailableForProtocolError) GRPCStatus() *status.Status {
 type MissingProgrammerError struct{}
 
 func (e *MissingProgrammerError) Error() string {
-	return tr("Missing programmer")
+	return i18n.Tr("Missing programmer")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -298,7 +296,7 @@ func (e *MissingProgrammerError) GRPCStatus() *status.Status {
 type ProgrammerRequiredForUploadError struct{}
 
 func (e *ProgrammerRequiredForUploadError) Error() string {
-	return tr("A programmer is required to upload")
+	return i18n.Tr("A programmer is required to upload")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -338,7 +336,7 @@ type ProgrammerNotFoundError struct {
 }
 
 func (e *ProgrammerNotFoundError) Error() string {
-	return composeErrorMsg(tr("Programmer '%s' not found", e.Programmer), e.Cause)
+	return composeErrorMsg(i18n.Tr("Programmer '%s' not found", e.Programmer), e.Cause)
 }
 
 func (e *ProgrammerNotFoundError) Unwrap() error {
@@ -357,7 +355,7 @@ type MonitorNotFoundError struct {
 }
 
 func (e *MonitorNotFoundError) Error() string {
-	return composeErrorMsg(tr("Monitor '%s' not found", e.Monitor), e.Cause)
+	return composeErrorMsg(i18n.Tr("Monitor '%s' not found", e.Monitor), e.Cause)
 }
 
 func (e *MonitorNotFoundError) Unwrap() error {
@@ -376,7 +374,7 @@ type InvalidPlatformPropertyError struct {
 }
 
 func (e *InvalidPlatformPropertyError) Error() string {
-	return tr("Invalid '%[1]s' property: %[2]s", e.Property, e.Value)
+	return i18n.Tr("Invalid '%[1]s' property: %[2]s", e.Property, e.Value)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -390,7 +388,7 @@ type MissingPlatformPropertyError struct {
 }
 
 func (e *MissingPlatformPropertyError) Error() string {
-	return tr("Property '%s' is undefined", e.Property)
+	return i18n.Tr("Property '%s' is undefined", e.Property)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -405,7 +403,7 @@ type PlatformNotFoundError struct {
 }
 
 func (e *PlatformNotFoundError) Error() string {
-	return composeErrorMsg(tr("Platform '%s' not found", e.Platform), e.Cause)
+	return composeErrorMsg(i18n.Tr("Platform '%s' not found", e.Platform), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -423,7 +421,7 @@ type PlatformLoadingError struct {
 }
 
 func (e *PlatformLoadingError) Error() string {
-	return composeErrorMsg(tr("Error loading hardware platform"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Error loading hardware platform"), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -444,7 +442,7 @@ type LibraryNotFoundError struct {
 }
 
 func (e *LibraryNotFoundError) Error() string {
-	return composeErrorMsg(tr("Library '%s' not found", e.Library), e.Cause)
+	return composeErrorMsg(i18n.Tr("Library '%s' not found", e.Library), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -463,7 +461,7 @@ type LibraryDependenciesResolutionFailedError struct {
 }
 
 func (e *LibraryDependenciesResolutionFailedError) Error() string {
-	return composeErrorMsg(tr("No valid dependencies solution found"), e.Cause)
+	return composeErrorMsg(i18n.Tr("No valid dependencies solution found"), e.Cause)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -481,7 +479,7 @@ type PlatformAlreadyAtTheLatestVersionError struct {
 }
 
 func (e *PlatformAlreadyAtTheLatestVersionError) Error() string {
-	return tr("Platform '%s' is already at the latest version", e.Platform)
+	return i18n.Tr("Platform '%s' is already at the latest version", e.Platform)
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -496,7 +494,7 @@ func (e *PlatformAlreadyAtTheLatestVersionError) GRPCStatus() *status.Status {
 type MissingSketchPathError struct{}
 
 func (e *MissingSketchPathError) Error() string {
-	return tr("Missing sketch path")
+	return i18n.Tr("Missing sketch path")
 }
 
 // GRPCStatus converts the error into a *status.Status
@@ -510,7 +508,7 @@ type CantCreateSketchError struct {
 }
 
 func (e *CantCreateSketchError) Error() string {
-	return composeErrorMsg(tr("Can't create sketch"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Can't create sketch"), e.Cause)
 }
 
 func (e *CantCreateSketchError) Unwrap() error {
@@ -523,7 +521,7 @@ type CantUpdateSketchError struct {
 }
 
 func (e *CantUpdateSketchError) Error() string {
-	return composeErrorMsg(tr("Can't update sketch"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Can't update sketch"), e.Cause)
 }
 
 func (e *CantUpdateSketchError) Unwrap() error {
@@ -536,7 +534,7 @@ type CantOpenSketchError struct {
 }
 
 func (e *CantOpenSketchError) Error() string {
-	return composeErrorMsg(tr("Can't open sketch"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Can't open sketch"), e.Cause)
 }
 
 func (e *CantOpenSketchError) Unwrap() error {
@@ -573,7 +571,7 @@ type FailedLibraryInstallError struct {
 }
 
 func (e *FailedLibraryInstallError) Error() string {
-	return composeErrorMsg(tr("Library install failed"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Library install failed"), e.Cause)
 }
 
 func (e *FailedLibraryInstallError) Unwrap() error {
@@ -667,7 +665,7 @@ type FailedMonitorError struct {
 }
 
 func (e *FailedMonitorError) Error() string {
-	return composeErrorMsg(tr("Port monitor error"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Port monitor error"), e.Cause)
 }
 
 func (e *FailedMonitorError) Unwrap() error {
@@ -780,7 +778,7 @@ type TempDirCreationFailedError struct {
 }
 
 func (e *TempDirCreationFailedError) Error() string {
-	return composeErrorMsg(tr("Cannot create temp dir"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Cannot create temp dir"), e.Cause)
 }
 
 func (e *TempDirCreationFailedError) Unwrap() error {
@@ -798,7 +796,7 @@ type TempFileCreationFailedError struct {
 }
 
 func (e *TempFileCreationFailedError) Error() string {
-	return composeErrorMsg(tr("Cannot create temp file"), e.Cause)
+	return composeErrorMsg(i18n.Tr("Cannot create temp file"), e.Cause)
 }
 
 func (e *TempFileCreationFailedError) Unwrap() error {
@@ -817,7 +815,7 @@ type SignatureVerificationFailedError struct {
 }
 
 func (e *SignatureVerificationFailedError) Error() string {
-	return composeErrorMsg(tr("'%s' has an invalid signature", e.File), e.Cause)
+	return composeErrorMsg(i18n.Tr("'%s' has an invalid signature", e.File), e.Cause)
 }
 
 func (e *SignatureVerificationFailedError) Unwrap() error {
@@ -838,7 +836,7 @@ type MultiplePlatformsError struct {
 }
 
 func (e *MultiplePlatformsError) Error() string {
-	return tr("Found %d platforms matching \"%s\": %s",
+	return i18n.Tr("Found %d platforms matching \"%s\": %s",
 		len(e.Platforms), e.UserPlatform, strings.Join(e.Platforms, ", "))
 }
 
@@ -857,7 +855,7 @@ type MultipleLibraryInstallDetected struct {
 }
 
 func (e *MultipleLibraryInstallDetected) Error() string {
-	res := tr("The library %s has multiple installations:", e.LibName) + "\n"
+	res := i18n.Tr("The library %s has multiple installations:", e.LibName) + "\n"
 	for _, lib := range e.LibsDir {
 		res += fmt.Sprintf("- %s\n", lib)
 	}
@@ -875,7 +873,7 @@ type InstanceNeedsReinitialization struct {
 }
 
 func (e *InstanceNeedsReinitialization) Error() string {
-	return tr("The instance is no longer valid and needs to be reinitialized")
+	return i18n.Tr("The instance is no longer valid and needs to be reinitialized")
 }
 
 // GRPCStatus converts the error into a *status.Status
diff --git a/commands/instances.go b/commands/instances.go
index 25d9fc19383..bd6764cf51d 100644
--- a/commands/instances.go
+++ b/commands/instances.go
@@ -17,6 +17,7 @@ package commands
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net/url"
 	"path/filepath"
@@ -49,13 +50,13 @@ func installTool(ctx context.Context, pm *packagemanager.PackageManager, tool *c
 	pme, release := pm.NewExplorer()
 	defer release()
 
-	taskCB(&rpc.TaskProgress{Name: tr("Downloading missing tool %s", tool)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Downloading missing tool %s", tool)})
 	if err := pme.DownloadToolRelease(ctx, tool, downloadCB); err != nil {
-		return fmt.Errorf(tr("downloading %[1]s tool: %[2]s"), tool, err)
+		return errors.New(i18n.Tr("downloading %[1]s tool: %[2]s", tool, err))
 	}
 	taskCB(&rpc.TaskProgress{Completed: true})
 	if err := pme.InstallTool(tool, taskCB, true); err != nil {
-		return fmt.Errorf(tr("installing %[1]s tool: %[2]s"), tool, err)
+		return errors.New(i18n.Tr("installing %[1]s tool: %[2]s", tool, err))
 	}
 	return nil
 }
@@ -75,7 +76,7 @@ func (s *arduinoCoreServerImpl) Create(ctx context.Context, req *rpc.CreateReque
 	if downloadsDir.NotExist() {
 		err := downloadsDir.MkdirAll()
 		if err != nil {
-			return nil, &cmderrors.PermissionDeniedError{Message: tr("Failed to create downloads directory"), Cause: err}
+			return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Failed to create downloads directory"), Cause: err}
 		}
 	}
 
@@ -86,7 +87,7 @@ func (s *arduinoCoreServerImpl) Create(ctx context.Context, req *rpc.CreateReque
 	if packagesDir.NotExist() {
 		err := packagesDir.MkdirAll()
 		if err != nil {
-			return nil, &cmderrors.PermissionDeniedError{Message: tr("Failed to create data directory"), Cause: err}
+			return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Failed to create data directory"), Cause: err}
 		}
 	}
 
@@ -182,7 +183,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 			if err != nil {
 				e := &cmderrors.InitFailedError{
 					Code:   codes.InvalidArgument,
-					Cause:  fmt.Errorf(tr("Invalid additional URL: %v", err)),
+					Cause:  errors.New(i18n.Tr("Invalid additional URL: %v", err)),
 					Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_INVALID_INDEX_URL,
 				}
 				responseError(e.GRPCStatus())
@@ -220,7 +221,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 				if err != nil {
 					e := &cmderrors.InitFailedError{
 						Code:   codes.FailedPrecondition,
-						Cause:  fmt.Errorf(tr("Loading index file: %v", err)),
+						Cause:  errors.New(i18n.Tr("Loading index file: %v", err)),
 						Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR,
 					}
 					responseError(e.GRPCStatus())
@@ -231,7 +232,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 			if err := pmb.LoadPackageIndex(URL); err != nil {
 				e := &cmderrors.InitFailedError{
 					Code:   codes.FailedPrecondition,
-					Cause:  fmt.Errorf(tr("Loading index file: %v", err)),
+					Cause:  errors.New(i18n.Tr("Loading index file: %v", err)),
 					Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR,
 				}
 				responseError(e.GRPCStatus())
@@ -271,7 +272,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 			if latest == nil {
 				e := &cmderrors.InitFailedError{
 					Code:   codes.Internal,
-					Cause:  fmt.Errorf(tr("can't find latest release of tool %s", name)),
+					Cause:  errors.New(i18n.Tr("can't find latest release of tool %s", name)),
 					Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR,
 				}
 				responseError(e.GRPCStatus())
@@ -341,7 +342,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 	logrus.WithField("index", indexFile).Info("Loading libraries index file")
 	li, err := librariesindex.LoadIndex(indexFile)
 	if err != nil {
-		s := status.Newf(codes.FailedPrecondition, tr("Loading index file: %v"), err)
+		s := status.Newf(codes.FailedPrecondition, i18n.Tr("Loading index file: %v", err))
 		responseError(s)
 		li = librariesindex.EmptyIndex
 	}
@@ -370,23 +371,23 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 
 			if !libDir.IsDir() {
 				// Download library
-				taskCallback(&rpc.TaskProgress{Name: tr("Downloading library %s", libraryRef)})
+				taskCallback(&rpc.TaskProgress{Name: i18n.Tr("Downloading library %s", libraryRef)})
 				libRelease, err := li.FindRelease(libraryRef.Library, libraryRef.Version)
 				if err != nil {
-					taskCallback(&rpc.TaskProgress{Name: tr("Library %s not found", libraryRef)})
+					taskCallback(&rpc.TaskProgress{Name: i18n.Tr("Library %s not found", libraryRef)})
 					err := &cmderrors.LibraryNotFoundError{Library: libraryRef.Library}
 					responseError(err.GRPCStatus())
 					continue
 				}
 				config, err := s.settings.DownloaderConfig()
 				if err != nil {
-					taskCallback(&rpc.TaskProgress{Name: tr("Error downloading library %s", libraryRef)})
+					taskCallback(&rpc.TaskProgress{Name: i18n.Tr("Error downloading library %s", libraryRef)})
 					e := &cmderrors.FailedLibraryInstallError{Cause: err}
 					responseError(e.GRPCStatus())
 					continue
 				}
 				if err := libRelease.Resource.Download(ctx, pme.DownloadDir, config, libRelease.String(), downloadCallback, ""); err != nil {
-					taskCallback(&rpc.TaskProgress{Name: tr("Error downloading library %s", libraryRef)})
+					taskCallback(&rpc.TaskProgress{Name: i18n.Tr("Error downloading library %s", libraryRef)})
 					e := &cmderrors.FailedLibraryInstallError{Cause: err}
 					responseError(e.GRPCStatus())
 					continue
@@ -394,9 +395,9 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
 				taskCallback(&rpc.TaskProgress{Completed: true})
 
 				// Install library
-				taskCallback(&rpc.TaskProgress{Name: tr("Installing library %s", libraryRef)})
+				taskCallback(&rpc.TaskProgress{Name: i18n.Tr("Installing library %s", libraryRef)})
 				if err := libRelease.Resource.Install(pme.DownloadDir, libRoot, libDir); err != nil {
-					taskCallback(&rpc.TaskProgress{Name: tr("Error installing library %s", libraryRef)})
+					taskCallback(&rpc.TaskProgress{Name: i18n.Tr("Error installing library %s", libraryRef)})
 					e := &cmderrors.FailedLibraryInstallError{Cause: err}
 					responseError(e.GRPCStatus())
 					continue
@@ -483,7 +484,7 @@ func (s *arduinoCoreServerImpl) UpdateLibrariesIndex(req *rpc.UpdateLibrariesInd
 	// Create the index directory if it doesn't exist
 	if err := indexDir.MkdirAll(); err != nil {
 		resultCB(rpc.IndexUpdateReport_STATUS_FAILED)
-		return &cmderrors.PermissionDeniedError{Message: tr("Could not create index directory"), Cause: err}
+		return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Could not create index directory"), Cause: err}
 	}
 
 	// Check if the index file is already up-to-date
@@ -559,8 +560,8 @@ func (s *arduinoCoreServerImpl) UpdateIndex(req *rpc.UpdateIndexRequest, stream
 		URL, err := url.Parse(u)
 		if err != nil {
 			logrus.Warnf("unable to parse additional URL: %s", u)
-			msg := fmt.Sprintf("%s: %v", tr("Unable to parse URL"), err)
-			downloadCB.Start(u, tr("Downloading index: %s", u))
+			msg := fmt.Sprintf("%s: %v", i18n.Tr("Unable to parse URL"), err)
+			downloadCB.Start(u, i18n.Tr("Downloading index: %s", u))
 			downloadCB.End(false, msg)
 			failed = true
 			result.UpdatedIndexes = append(result.GetUpdatedIndexes(), report(URL, rpc.IndexUpdateReport_STATUS_FAILED))
@@ -577,8 +578,8 @@ func (s *arduinoCoreServerImpl) UpdateIndex(req *rpc.UpdateIndexRequest, stream
 				path = paths.New(URL.Path[1:])
 			}
 			if _, err := packageindex.LoadIndexNoSign(path); err != nil {
-				msg := fmt.Sprintf("%s: %v", tr("Invalid package index in %s", path), err)
-				downloadCB.Start(u, tr("Downloading index: %s", filepath.Base(URL.Path)))
+				msg := fmt.Sprintf("%s: %v", i18n.Tr("Invalid package index in %s", path), err)
+				downloadCB.Start(u, i18n.Tr("Downloading index: %s", filepath.Base(URL.Path)))
 				downloadCB.End(false, msg)
 				failed = true
 				result.UpdatedIndexes = append(result.GetUpdatedIndexes(), report(URL, rpc.IndexUpdateReport_STATUS_FAILED))
@@ -592,8 +593,8 @@ func (s *arduinoCoreServerImpl) UpdateIndex(req *rpc.UpdateIndexRequest, stream
 		indexResource := resources.IndexResource{URL: URL}
 		indexFileName, err := indexResource.IndexFileName()
 		if err != nil {
-			downloadCB.Start(u, tr("Downloading index: %s", filepath.Base(URL.Path)))
-			downloadCB.End(false, tr("Invalid index URL: %s", err))
+			downloadCB.Start(u, i18n.Tr("Downloading index: %s", filepath.Base(URL.Path)))
+			downloadCB.End(false, i18n.Tr("Invalid index URL: %s", err))
 			failed = true
 			result.UpdatedIndexes = append(result.GetUpdatedIndexes(), report(URL, rpc.IndexUpdateReport_STATUS_FAILED))
 			continue
@@ -609,8 +610,8 @@ func (s *arduinoCoreServerImpl) UpdateIndex(req *rpc.UpdateIndexRequest, stream
 
 		config, err := s.settings.DownloaderConfig()
 		if err != nil {
-			downloadCB.Start(u, tr("Downloading index: %s", filepath.Base(URL.Path)))
-			downloadCB.End(false, tr("Invalid network configuration: %s", err))
+			downloadCB.Start(u, i18n.Tr("Downloading index: %s", filepath.Base(URL.Path)))
+			downloadCB.End(false, i18n.Tr("Invalid network configuration: %s", err))
 			failed = true
 			continue
 		}
@@ -630,7 +631,7 @@ func (s *arduinoCoreServerImpl) UpdateIndex(req *rpc.UpdateIndexRequest, stream
 		Message: &rpc.UpdateIndexResponse_Result_{Result: result},
 	})
 	if failed {
-		return &cmderrors.FailedDownloadError{Message: tr("Some indexes could not be updated.")}
+		return &cmderrors.FailedDownloadError{Message: i18n.Tr("Some indexes could not be updated.")}
 	}
 	return nil
 }
@@ -657,7 +658,7 @@ func firstUpdate(ctx context.Context, srv rpc.ArduinoCoreServiceServer, instance
 		packageIndexFileName, err := (&resources.IndexResource{URL: URL}).IndexFileName()
 		if err != nil {
 			return &cmderrors.FailedDownloadError{
-				Message: tr("Error downloading index '%s'", URL),
+				Message: i18n.Tr("Error downloading index '%s'", URL),
 				Cause:   &cmderrors.InvalidURLError{}}
 		}
 		packageIndexFile := indexDir.Join(packageIndexFileName)
diff --git a/commands/service_board_list.go b/commands/service_board_list.go
index aff1085c9c2..a5376cb9f1f 100644
--- a/commands/service_board_list.go
+++ b/commands/service_board_list.go
@@ -33,6 +33,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
 	"github.com/arduino/arduino-cli/internal/cli/configuration"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/arduino-cli/internal/inventory"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-properties-orderedmap"
@@ -74,10 +75,10 @@ func cachedAPIByVidPid(vid, pid string, settings *configuration.Settings) ([]*rp
 func apiByVidPid(vid, pid string, settings *configuration.Settings) ([]*rpc.BoardListItem, error) {
 	// ensure vid and pid are valid before hitting the API
 	if !validVidPid.MatchString(vid) {
-		return nil, errors.New(tr("Invalid vid value: '%s'", vid))
+		return nil, errors.New(i18n.Tr("Invalid vid value: '%s'", vid))
 	}
 	if !validVidPid.MatchString(pid) {
-		return nil, errors.New(tr("Invalid pid value: '%s'", pid))
+		return nil, errors.New(i18n.Tr("Invalid pid value: '%s'", pid))
 	}
 
 	url := fmt.Sprintf("%s/%s/%s", vidPidURL, vid, pid)
@@ -86,19 +87,19 @@ func apiByVidPid(vid, pid string, settings *configuration.Settings) ([]*rpc.Boar
 
 	httpClient, err := settings.NewHttpClient()
 	if err != nil {
-		return nil, fmt.Errorf("%s: %w", tr("failed to initialize http client"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("failed to initialize http client"), err)
 	}
 
 	res, err := httpClient.Do(req)
 	if err != nil {
-		return nil, fmt.Errorf("%s: %w", tr("error querying Arduino Cloud Api"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("error querying Arduino Cloud Api"), err)
 	}
 	if res.StatusCode == 404 {
 		// This is not an error, it just means that the board is not recognized
 		return nil, nil
 	}
 	if res.StatusCode >= 400 {
-		return nil, errors.New(tr("the server responded with status %s", res.Status))
+		return nil, errors.New(i18n.Tr("the server responded with status %s", res.Status))
 	}
 
 	resp, err := io.ReadAll(res.Body)
@@ -111,12 +112,12 @@ func apiByVidPid(vid, pid string, settings *configuration.Settings) ([]*rpc.Boar
 
 	var dat map[string]interface{}
 	if err := json.Unmarshal(resp, &dat); err != nil {
-		return nil, fmt.Errorf("%s: %w", tr("error processing response from server"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("error processing response from server"), err)
 	}
 	name, nameFound := dat["name"].(string)
 	fqbn, fbqnFound := dat["fqbn"].(string)
 	if !nameFound || !fbqnFound {
-		return nil, errors.New(tr("wrong format in server response"))
+		return nil, errors.New(i18n.Tr("wrong format in server response"))
 	}
 
 	return []*rpc.BoardListItem{
@@ -269,7 +270,7 @@ func BoardListWatchProxyToChan(ctx context.Context) (rpc.ArduinoCoreService_Boar
 func (s *arduinoCoreServerImpl) BoardListWatch(req *rpc.BoardListWatchRequest, stream rpc.ArduinoCoreService_BoardListWatchServer) error {
 	syncSend := NewSynchronizedSend(stream.Send)
 	if req.GetInstance() == nil {
-		err := fmt.Errorf(tr("no instance specified"))
+		err := errors.New(i18n.Tr("no instance specified"))
 		syncSend.Send(&rpc.BoardListWatchResponse{
 			EventType: "error",
 			Error:     err.Error(),
diff --git a/commands/service_compile.go b/commands/service_compile.go
index 9722c72671a..3dbc4e3fbc7 100644
--- a/commands/service_compile.go
+++ b/commands/service_compile.go
@@ -32,6 +32,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
 	"github.com/arduino/arduino-cli/internal/arduino/utils"
 	"github.com/arduino/arduino-cli/internal/buildcache"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/arduino-cli/internal/inventory"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
@@ -117,7 +118,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 		if targetPlatform == nil {
 			return &cmderrors.PlatformNotFoundError{
 				Platform: fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch),
-				Cause:    fmt.Errorf(tr("platform not installed")),
+				Cause:    errors.New(i18n.Tr("platform not installed")),
 			}
 		}
 		return &cmderrors.InvalidFQBNError{Cause: err}
@@ -151,7 +152,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 	encryptProp := boardBuildProperties.ContainsKey("build.keys.encrypt_key")
 	// we verify that all the properties for the secure boot keys are defined or none of them is defined.
 	if !(keychainProp == signProp && signProp == encryptProp) {
-		return fmt.Errorf(tr("Firmware encryption/signing requires all the following properties to be defined: %s", "build.keys.keychain, build.keys.sign_key, build.keys.encrypt_key"))
+		return errors.New(i18n.Tr("Firmware encryption/signing requires all the following properties to be defined: %s", "build.keys.keychain, build.keys.sign_key, build.keys.encrypt_key"))
 	}
 
 	// Generate or retrieve build path
@@ -168,7 +169,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 		buildPath = sk.DefaultBuildPath()
 	}
 	if err = buildPath.MkdirAll(); err != nil {
-		return &cmderrors.PermissionDeniedError{Message: tr("Cannot create build directory"), Cause: err}
+		return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Cannot create build directory"), Cause: err}
 	}
 	buildcache.New(buildPath.Parent()).GetOrCreate(buildPath.Base())
 	// cache is purged after compilation to not remove entries that might be required
@@ -183,10 +184,10 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 	} else {
 		buildCachePath, err := paths.New(req.GetBuildCachePath()).Abs()
 		if err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Cannot create build cache directory"), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Cannot create build cache directory"), Cause: err}
 		}
 		if err := buildCachePath.MkdirAll(); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Cannot create build cache directory"), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Cannot create build cache directory"), Cause: err}
 		}
 		coreBuildCachePath = buildCachePath.Join("core")
 	}
@@ -247,11 +248,11 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 	)
 	if err != nil {
 		if strings.Contains(err.Error(), "invalid build properties") {
-			return &cmderrors.InvalidArgumentError{Message: tr("Invalid build properties"), Cause: err}
+			return &cmderrors.InvalidArgumentError{Message: i18n.Tr("Invalid build properties"), Cause: err}
 		}
 		if errors.Is(err, builder.ErrSketchCannotBeLocatedInBuildPath) {
 			return &cmderrors.CompileFailedError{
-				Message: tr("Sketch cannot be located in build path. Please specify a different build path"),
+				Message: i18n.Tr("Sketch cannot be located in build path. Please specify a different build path"),
 			}
 		}
 		return &cmderrors.CompileFailedError{Message: err.Error()}
@@ -303,7 +304,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 		for _, lib := range sketchBuilder.ImportedLibraries() {
 			rpcLib, err := lib.ToRPCLibrary()
 			if err != nil {
-				msg := tr("Error getting information for library %s", lib.Name) + ": " + err.Error() + "\n"
+				msg := i18n.Tr("Error getting information for library %s", lib.Name) + ": " + err.Error() + "\n"
 				errStream.Write([]byte(msg))
 			}
 			importedLibs = append(importedLibs, rpcLib)
@@ -326,13 +327,13 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 		}
 		outStream.Write([]byte(fmt.Sprintf("FQBN: %s\n", normalizedFQBN)))
 		core = core[strings.Index(core, ":")+1:]
-		outStream.Write([]byte(tr("Using board '%[1]s' from platform in folder: %[2]s", targetBoard.BoardID, targetPlatform.InstallDir) + "\n"))
-		outStream.Write([]byte(tr("Using core '%[1]s' from platform in folder: %[2]s", core, buildPlatform.InstallDir) + "\n"))
+		outStream.Write([]byte(i18n.Tr("Using board '%[1]s' from platform in folder: %[2]s", targetBoard.BoardID, targetPlatform.InstallDir) + "\n"))
+		outStream.Write([]byte(i18n.Tr("Using core '%[1]s' from platform in folder: %[2]s", core, buildPlatform.InstallDir) + "\n"))
 		outStream.Write([]byte("\n"))
 	}
 	if !targetBoard.Properties.ContainsKey("build.board") {
 		outStream.Write([]byte(
-			tr("Warning: Board %[1]s doesn't define a %[2]s preference. Auto-set to: %[3]s",
+			i18n.Tr("Warning: Board %[1]s doesn't define a %[2]s preference. Auto-set to: %[3]s",
 				targetBoard.String(), "'build.board'", sketchBuilder.GetBuildProperties().Get("build.board")) + "\n"))
 	}
 
@@ -364,7 +365,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 		if !buildPath.EqualsTo(exportPath) {
 			logrus.WithField("path", exportPath).Trace("Saving sketch to export path.")
 			if err := exportPath.MkdirAll(); err != nil {
-				return &cmderrors.PermissionDeniedError{Message: tr("Error creating output dir"), Cause: err}
+				return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error creating output dir"), Cause: err}
 			}
 
 			baseName, ok := sketchBuilder.GetBuildProperties().GetOk("build.project_name") // == "sketch.ino"
@@ -373,14 +374,14 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu
 			}
 			buildFiles, err := sketchBuilder.GetBuildPath().ReadDir()
 			if err != nil {
-				return &cmderrors.PermissionDeniedError{Message: tr("Error reading build directory"), Cause: err}
+				return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error reading build directory"), Cause: err}
 			}
 			buildFiles.FilterPrefix(baseName)
 			for _, buildFile := range buildFiles {
 				exportedFile := exportPath.Join(buildFile.Base())
 				logrus.WithField("src", buildFile).WithField("dest", exportedFile).Trace("Copying artifact.")
 				if err = buildFile.CopyTo(exportedFile); err != nil {
-					return &cmderrors.PermissionDeniedError{Message: tr("Error copying output file %s", buildFile), Cause: err}
+					return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error copying output file %s", buildFile), Cause: err}
 				}
 			}
 		}
diff --git a/commands/service_debug.go b/commands/service_debug.go
index 974b75c5267..d17c99622a6 100644
--- a/commands/service_debug.go
+++ b/commands/service_debug.go
@@ -20,6 +20,7 @@ import (
 	"errors"
 	"os"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -36,7 +37,7 @@ func (s *arduinoCoreServerImpl) Debug(stream rpc.ArduinoCoreService_DebugServer)
 	// Ensure it's a config message and not data
 	req := msg.GetDebugRequest()
 	if req == nil {
-		return errors.New(tr("First message must contain debug request, not data"))
+		return errors.New(i18n.Tr("First message must contain debug request, not data"))
 	}
 
 	// Launch debug recipe attaching stdin and out to grpc streaming
diff --git a/commands/service_debug_config.go b/commands/service_debug_config.go
index 0f4040011f8..393a81811e6 100644
--- a/commands/service_debug_config.go
+++ b/commands/service_debug_config.go
@@ -29,6 +29,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
@@ -172,10 +173,10 @@ func getDebugProperties(req *rpc.GetDebugConfigRequest, pme *packagemanager.Expl
 	}
 	if !skipSketchChecks {
 		if !importPath.Exist() {
-			return nil, &cmderrors.NotFoundError{Message: tr("Compiled sketch not found in %s", importPath)}
+			return nil, &cmderrors.NotFoundError{Message: i18n.Tr("Compiled sketch not found in %s", importPath)}
 		}
 		if !importPath.IsDir() {
-			return nil, &cmderrors.NotFoundError{Message: tr("Expected compiled sketch in directory %s, but is a file instead", importPath)}
+			return nil, &cmderrors.NotFoundError{Message: i18n.Tr("Expected compiled sketch in directory %s, but is a file instead", importPath)}
 		}
 	}
 	toolProperties.SetPath("build.path", importPath)
@@ -202,7 +203,7 @@ func getDebugProperties(req *rpc.GetDebugConfigRequest, pme *packagemanager.Expl
 	}
 
 	if !debugProperties.ContainsKey("executable") || debugProperties.Get("executable") == "" {
-		return nil, &cmderrors.FailedDebugError{Message: tr("Debugging not supported for board %s", req.GetFqbn())}
+		return nil, &cmderrors.FailedDebugError{Message: i18n.Tr("Debugging not supported for board %s", req.GetFqbn())}
 	}
 
 	server := debugProperties.Get("server")
diff --git a/commands/service_debug_run.go b/commands/service_debug_run.go
index 1b76ec05e68..94cdc43efa8 100644
--- a/commands/service_debug_run.go
+++ b/commands/service_debug_run.go
@@ -27,6 +27,7 @@ import (
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/commands/internal/instances"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -65,7 +66,7 @@ func Debug(ctx context.Context, req *rpc.GetDebugConfigRequest, inStream io.Read
 
 	cmd, err := paths.NewProcess(pme.GetEnvVarsForSpawnedProcess(), commandLine...)
 	if err != nil {
-		return nil, &cmderrors.FailedDebugError{Message: tr("Cannot execute debug tool"), Cause: err}
+		return nil, &cmderrors.FailedDebugError{Message: i18n.Tr("Cannot execute debug tool"), Cause: err}
 	}
 
 	// Get stdIn pipe from tool
@@ -140,7 +141,7 @@ func getCommandLine(req *rpc.GetDebugConfigRequest, pme *packagemanager.Explorer
 		}
 		gdbPath = paths.New(debugInfo.GetToolchainPath()).Join(gdbexecutable)
 	default:
-		return nil, &cmderrors.FailedDebugError{Message: tr("Toolchain '%s' is not supported", debugInfo.GetToolchain())}
+		return nil, &cmderrors.FailedDebugError{Message: i18n.Tr("Toolchain '%s' is not supported", debugInfo.GetToolchain())}
 	}
 	add(gdbPath.String())
 
@@ -184,7 +185,7 @@ func getCommandLine(req *rpc.GetDebugConfigRequest, pme *packagemanager.Explorer
 		add(serverCmd)
 
 	default:
-		return nil, &cmderrors.FailedDebugError{Message: tr("GDB server '%s' is not supported", debugInfo.GetServer())}
+		return nil, &cmderrors.FailedDebugError{Message: i18n.Tr("GDB server '%s' is not supported", debugInfo.GetServer())}
 	}
 
 	// Add executable
diff --git a/commands/service_library_download.go b/commands/service_library_download.go
index c6a6bb3f0f6..2384d59396f 100644
--- a/commands/service_library_download.go
+++ b/commands/service_library_download.go
@@ -22,6 +22,7 @@ import (
 	"github.com/arduino/arduino-cli/commands/internal/instances"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex"
 	"github.com/arduino/arduino-cli/internal/cli/configuration"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 )
@@ -84,13 +85,13 @@ func (s *arduinoCoreServerImpl) LibraryDownload(req *rpc.LibraryDownloadRequest,
 func downloadLibrary(ctx context.Context, downloadsDir *paths.Path, libRelease *librariesindex.Release,
 	downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, queryParameter string, settings *configuration.Settings) error {
 
-	taskCB(&rpc.TaskProgress{Name: tr("Downloading %s", libRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Downloading %s", libRelease)})
 	config, err := settings.DownloaderConfig()
 	if err != nil {
-		return &cmderrors.FailedDownloadError{Message: tr("Can't download library"), Cause: err}
+		return &cmderrors.FailedDownloadError{Message: i18n.Tr("Can't download library"), Cause: err}
 	}
 	if err := libRelease.Resource.Download(ctx, downloadsDir, config, libRelease.String(), downloadCB, queryParameter); err != nil {
-		return &cmderrors.FailedDownloadError{Message: tr("Can't download library"), Cause: err}
+		return &cmderrors.FailedDownloadError{Message: i18n.Tr("Can't download library"), Cause: err}
 	}
 	taskCB(&rpc.TaskProgress{Completed: true})
 
diff --git a/commands/service_library_install.go b/commands/service_library_install.go
index e07a748da24..ca1531ac267 100644
--- a/commands/service_library_install.go
+++ b/commands/service_library_install.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/libraries"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -88,7 +89,7 @@ func (s *arduinoCoreServerImpl) LibraryInstall(req *rpc.LibraryInstallRequest, s
 			if existingDep, has := toInstall[dep.GetName()]; has {
 				if existingDep.GetVersionRequired() != dep.GetVersionRequired() {
 					err := errors.New(
-						tr("two different versions of the library %[1]s are required: %[2]s and %[3]s",
+						i18n.Tr("two different versions of the library %[1]s are required: %[2]s and %[3]s",
 							dep.GetName(), dep.GetVersionRequired(), existingDep.GetVersionRequired()))
 					return &cmderrors.LibraryDependenciesResolutionFailedError{Cause: err}
 				}
@@ -131,13 +132,13 @@ func (s *arduinoCoreServerImpl) LibraryInstall(req *rpc.LibraryInstallRequest, s
 			return err
 		}
 		if installTask.UpToDate {
-			taskCB(&rpc.TaskProgress{Message: tr("Already installed %s", libRelease), Completed: true})
+			taskCB(&rpc.TaskProgress{Message: i18n.Tr("Already installed %s", libRelease), Completed: true})
 			continue
 		}
 
 		if req.GetNoOverwrite() {
 			if installTask.ReplacedLib != nil {
-				return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", libRelease, installTask.ReplacedLib))
+				return errors.New(i18n.Tr("Library %[1]s is already installed, but with a different version: %[2]s", libRelease, installTask.ReplacedLib))
 			}
 		}
 		libReleasesToInstall[libRelease] = installTask
@@ -179,14 +180,14 @@ func (s *arduinoCoreServerImpl) LibraryInstall(req *rpc.LibraryInstallRequest, s
 }
 
 func installLibrary(lmi *librariesmanager.Installer, downloadsDir *paths.Path, libRelease *librariesindex.Release, installTask *librariesmanager.LibraryInstallPlan, taskCB rpc.TaskProgressCB) error {
-	taskCB(&rpc.TaskProgress{Name: tr("Installing %s", libRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Installing %s", libRelease)})
 	logrus.WithField("library", libRelease).Info("Installing library")
 
 	if libReplaced := installTask.ReplacedLib; libReplaced != nil {
-		taskCB(&rpc.TaskProgress{Message: tr("Replacing %[1]s with %[2]s", libReplaced, libRelease)})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Replacing %[1]s with %[2]s", libReplaced, libRelease)})
 		if err := lmi.Uninstall(libReplaced); err != nil {
 			return &cmderrors.FailedLibraryInstallError{
-				Cause: fmt.Errorf("%s: %s", tr("could not remove old library"), err)}
+				Cause: fmt.Errorf("%s: %s", i18n.Tr("could not remove old library"), err)}
 		}
 	}
 
@@ -196,7 +197,7 @@ func installLibrary(lmi *librariesmanager.Installer, downloadsDir *paths.Path, l
 		return &cmderrors.FailedLibraryInstallError{Cause: err}
 	}
 
-	taskCB(&rpc.TaskProgress{Message: tr("Installed %s", libRelease), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("Installed %s", libRelease), Completed: true})
 	return nil
 }
 
@@ -230,7 +231,7 @@ func (s *arduinoCoreServerImpl) ZipLibraryInstall(req *rpc.ZipLibraryInstallRequ
 	if err := lmi.InstallZipLib(ctx, paths.New(req.GetPath()), req.GetOverwrite()); err != nil {
 		return &cmderrors.FailedLibraryInstallError{Cause: err}
 	}
-	taskCB(&rpc.TaskProgress{Message: tr("Library installed"), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("Library installed"), Completed: true})
 	syncSend.Send(&rpc.ZipLibraryInstallResponse{
 		Message: &rpc.ZipLibraryInstallResponse_Result_{
 			Result: &rpc.ZipLibraryInstallResponse_Result{},
@@ -270,7 +271,7 @@ func (s *arduinoCoreServerImpl) GitLibraryInstall(req *rpc.GitLibraryInstallRequ
 	if err := lmi.InstallGitLib(req.GetUrl(), req.GetOverwrite()); err != nil {
 		return &cmderrors.FailedLibraryInstallError{Cause: err}
 	}
-	taskCB(&rpc.TaskProgress{Message: tr("Library installed"), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("Library installed"), Completed: true})
 	syncSend.Send(&rpc.GitLibraryInstallResponse{
 		Message: &rpc.GitLibraryInstallResponse_Result_{
 			Result: &rpc.GitLibraryInstallResponse_Result{},
diff --git a/commands/service_library_list.go b/commands/service_library_list.go
index be293c6161d..35104caf08b 100644
--- a/commands/service_library_list.go
+++ b/commands/service_library_list.go
@@ -26,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesresolver"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -111,7 +112,7 @@ func (s *arduinoCoreServerImpl) LibraryList(ctx context.Context, req *rpc.Librar
 		}
 		rpcLib, err := lib.Library.ToRPCLibrary()
 		if err != nil {
-			return nil, &cmderrors.PermissionDeniedError{Message: tr("Error getting information for library %s", lib.Library.Name), Cause: err}
+			return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error getting information for library %s", lib.Library.Name), Cause: err}
 		}
 		installedLibs = append(installedLibs, &rpc.InstalledLibrary{
 			Library: rpcLib,
diff --git a/commands/service_library_resolve_deps.go b/commands/service_library_resolve_deps.go
index c50cc2d9f6a..83cc7f1f737 100644
--- a/commands/service_library_resolve_deps.go
+++ b/commands/service_library_resolve_deps.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/libraries"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	semver "go.bug.st/relaxed-semver"
 )
@@ -82,7 +83,7 @@ func libraryResolveDependencies(lme *librariesmanager.Explorer, li *librariesind
 		// Check if there is a problem with the first level deps
 		for _, directDep := range reqLibRelease.GetDependencies() {
 			if _, ok := li.Libraries[directDep.GetName()]; !ok {
-				err := errors.New(tr("dependency '%s' is not available", directDep.GetName()))
+				err := errors.New(i18n.Tr("dependency '%s' is not available", directDep.GetName()))
 				return nil, &cmderrors.LibraryDependenciesResolutionFailedError{Cause: err}
 			}
 		}
diff --git a/commands/service_library_uninstall.go b/commands/service_library_uninstall.go
index add0b7be491..27b5acbfde5 100644
--- a/commands/service_library_uninstall.go
+++ b/commands/service_library_uninstall.go
@@ -21,6 +21,7 @@ import (
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/commands/internal/instances"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 )
@@ -59,7 +60,7 @@ func (s *arduinoCoreServerImpl) LibraryUninstall(req *rpc.LibraryUninstallReques
 
 	libs := lmi.FindByReference(req.GetName(), version, libraries.User)
 	if len(libs) == 0 {
-		taskCB(&rpc.TaskProgress{Message: tr("Library %s is not installed", req.GetName()), Completed: true})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Library %s is not installed", req.GetName()), Completed: true})
 		syncSend.Send(&rpc.LibraryUninstallResponse{
 			Message: &rpc.LibraryUninstallResponse_Result_{Result: &rpc.LibraryUninstallResponse_Result{}},
 		})
@@ -67,7 +68,7 @@ func (s *arduinoCoreServerImpl) LibraryUninstall(req *rpc.LibraryUninstallReques
 	}
 
 	if len(libs) == 1 {
-		taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s", libs)})
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Uninstalling %s", libs)})
 		lmi.Uninstall(libs[0])
 		taskCB(&rpc.TaskProgress{Completed: true})
 		syncSend.Send(&rpc.LibraryUninstallResponse{
@@ -83,6 +84,6 @@ func (s *arduinoCoreServerImpl) LibraryUninstall(req *rpc.LibraryUninstallReques
 	return &cmderrors.MultipleLibraryInstallDetected{
 		LibName: libs[0].Name,
 		LibsDir: libsDir,
-		Message: tr("Automatic library uninstall can't be performed in this case, please manually remove them."),
+		Message: i18n.Tr("Automatic library uninstall can't be performed in this case, please manually remove them."),
 	}
 }
diff --git a/commands/service_library_upgrade.go b/commands/service_library_upgrade.go
index 4b0fa20223d..d63e01a4c3a 100644
--- a/commands/service_library_upgrade.go
+++ b/commands/service_library_upgrade.go
@@ -20,6 +20,7 @@ import (
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/commands/internal/instances"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -133,7 +134,7 @@ func (s *arduinoCoreServerImpl) LibraryUpgrade(req *rpc.LibraryUpgradeRequest, s
 	}
 	if lib.Available == nil {
 		// library already at the latest version
-		taskCB(&rpc.TaskProgress{Message: tr("Library %s is already at the latest version", name), Completed: true})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Library %s is already at the latest version", name), Completed: true})
 	} else {
 		// Install update
 		if err := s.libraryUpgrade(ctx, req.GetInstance(), []*installedLib{lib}, downloadCB, taskCB); err != nil {
diff --git a/commands/service_monitor.go b/commands/service_monitor.go
index 697483b05f5..7c47e201ada 100644
--- a/commands/service_monitor.go
+++ b/commands/service_monitor.go
@@ -27,6 +27,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
 	pluggableMonitor "github.com/arduino/arduino-cli/internal/arduino/monitor"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-properties-orderedmap"
 	"github.com/djherbis/buffer"
@@ -265,7 +266,7 @@ func findMonitorAndSettingsForProtocolAndBoard(pme *packagemanager.Explorer, pro
 			cmdLine := boardProperties.ExpandPropsInString(recipe)
 			cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false)
 			if err != nil {
-				return nil, nil, &cmderrors.InvalidArgumentError{Message: tr("Invalid recipe in platform.txt"), Cause: err}
+				return nil, nil, &cmderrors.InvalidArgumentError{Message: i18n.Tr("Invalid recipe in platform.txt"), Cause: err}
 			}
 			id := fmt.Sprintf("%s-%s", boardPlatform, protocol)
 			return pluggableMonitor.New(id, cmdArgs...), boardSettings, nil
diff --git a/commands/service_platform_download.go b/commands/service_platform_download.go
index 9fb39255125..1f542d3abf1 100644
--- a/commands/service_platform_download.go
+++ b/commands/service_platform_download.go
@@ -21,12 +21,9 @@ import (
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/commands/internal/instances"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
-	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
-var tr = i18n.Tr
-
 // PlatformDownloadStreamResponseToCallbackFunction returns a gRPC stream to be used in PlatformDownload that sends
 // all responses to the callback function.
 func PlatformDownloadStreamResponseToCallbackFunction(ctx context.Context, downloadCB rpc.DownloadProgressCB) rpc.ArduinoCoreService_PlatformDownloadServer {
diff --git a/commands/service_platform_install.go b/commands/service_platform_install.go
index 2249297d97d..6a9583fa429 100644
--- a/commands/service_platform_install.go
+++ b/commands/service_platform_install.go
@@ -22,6 +22,7 @@ import (
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/commands/internal/instances"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -82,15 +83,15 @@ func (s *arduinoCoreServerImpl) PlatformInstall(req *rpc.PlatformInstallRequest,
 
 		// Prerequisite checks before install
 		if platformRelease.IsInstalled() {
-			taskCB(&rpc.TaskProgress{Name: tr("Platform %s already installed", platformRelease), Completed: true})
+			taskCB(&rpc.TaskProgress{Name: i18n.Tr("Platform %s already installed", platformRelease), Completed: true})
 			return nil
 		}
 
 		if req.GetNoOverwrite() {
 			if installed := pme.GetInstalledPlatformRelease(platformRelease.Platform); installed != nil {
 				return fmt.Errorf("%s: %s",
-					tr("Platform %s already installed", installed),
-					tr("could not overwrite"))
+					i18n.Tr("Platform %s already installed", installed),
+					i18n.Tr("could not overwrite"))
 			}
 		}
 
diff --git a/commands/service_platform_uninstall.go b/commands/service_platform_uninstall.go
index 8417fdd4a60..cf21d91a8ad 100644
--- a/commands/service_platform_uninstall.go
+++ b/commands/service_platform_uninstall.go
@@ -21,6 +21,7 @@ import (
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/commands/internal/instances"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -85,7 +86,7 @@ func platformUninstall(_ context.Context, req *rpc.PlatformUninstallRequest, tas
 
 	platform, tools, err := pme.FindPlatformReleaseDependencies(ref)
 	if err != nil {
-		return &cmderrors.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err}
+		return &cmderrors.NotFoundError{Message: i18n.Tr("Can't find dependencies for platform %s", ref), Cause: err}
 	}
 
 	// TODO: pass context
@@ -95,7 +96,7 @@ func platformUninstall(_ context.Context, req *rpc.PlatformUninstallRequest, tas
 
 	for _, tool := range tools {
 		if !pme.IsToolRequired(tool) {
-			taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
+			taskCB(&rpc.TaskProgress{Name: i18n.Tr("Uninstalling %s, tool is no more required", tool)})
 			pme.UninstallTool(tool, taskCB, req.GetSkipPreUninstall())
 		}
 	}
diff --git a/commands/service_sketch_archive.go b/commands/service_sketch_archive.go
index 67515406382..c4cde916321 100644
--- a/commands/service_sketch_archive.go
+++ b/commands/service_sketch_archive.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
 )
@@ -53,7 +54,7 @@ func (s *arduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.Arch
 
 	archivePath, err = archivePath.Clean().Abs()
 	if err != nil {
-		return nil, &cmderrors.PermissionDeniedError{Message: tr("Error getting absolute path of sketch archive"), Cause: err}
+		return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error getting absolute path of sketch archive"), Cause: err}
 	}
 
 	// Makes archivePath point to a zip file
@@ -65,19 +66,19 @@ func (s *arduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.Arch
 
 	if !req.GetOverwrite() {
 		if archivePath.Exist() {
-			return nil, &cmderrors.InvalidArgumentError{Message: tr("Archive already exists")}
+			return nil, &cmderrors.InvalidArgumentError{Message: i18n.Tr("Archive already exists")}
 		}
 	}
 
 	filesToZip, err := sketchPath.ReadDirRecursive()
 	if err != nil {
-		return nil, &cmderrors.PermissionDeniedError{Message: tr("Error reading sketch files"), Cause: err}
+		return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error reading sketch files"), Cause: err}
 	}
 	filesToZip.FilterOutDirs()
 
 	archive, err := archivePath.Create()
 	if err != nil {
-		return nil, &cmderrors.PermissionDeniedError{Message: tr("Error creating sketch archive"), Cause: err}
+		return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error creating sketch archive"), Cause: err}
 	}
 	defer archive.Close()
 
@@ -89,7 +90,7 @@ func (s *arduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.Arch
 		if !req.GetIncludeBuildDir() {
 			filePath, err := sketchPath.Parent().RelTo(f)
 			if err != nil {
-				return nil, &cmderrors.PermissionDeniedError{Message: tr("Error calculating relative file path"), Cause: err}
+				return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error calculating relative file path"), Cause: err}
 			}
 
 			// Skips build folder
@@ -101,7 +102,7 @@ func (s *arduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.Arch
 		// We get the parent path since we want the archive to unpack as a folder.
 		// If we don't do this the archive would contain all the sketch files as top level.
 		if err := addFileToSketchArchive(zipWriter, f, sketchPath.Parent()); err != nil {
-			return nil, &cmderrors.PermissionDeniedError{Message: tr("Error adding file to sketch archive"), Cause: err}
+			return nil, &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error adding file to sketch archive"), Cause: err}
 		}
 	}
 
diff --git a/commands/service_sketch_new.go b/commands/service_sketch_new.go
index b0c9c079f73..ca3143e31b9 100644
--- a/commands/service_sketch_new.go
+++ b/commands/service_sketch_new.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
 )
@@ -62,7 +63,7 @@ func (s *arduinoCoreServerImpl) NewSketch(ctx context.Context, req *rpc.NewSketc
 	sketchMainFilePath := sketchDirPath.Join(sketchName + globals.MainFileValidExtension)
 	if !req.GetOverwrite() {
 		if sketchMainFilePath.Exist() {
-			return nil, &cmderrors.CantCreateSketchError{Cause: errors.New(tr(".ino file already exists"))}
+			return nil, &cmderrors.CantCreateSketchError{Cause: errors.New(i18n.Tr(".ino file already exists"))}
 		}
 	}
 	if err := sketchMainFilePath.WriteFile(emptySketch); err != nil {
@@ -74,20 +75,20 @@ func (s *arduinoCoreServerImpl) NewSketch(ctx context.Context, req *rpc.NewSketc
 
 func validateSketchName(name string) error {
 	if name == "" {
-		return &cmderrors.CantCreateSketchError{Cause: errors.New(tr("sketch name cannot be empty"))}
+		return &cmderrors.CantCreateSketchError{Cause: errors.New(i18n.Tr("sketch name cannot be empty"))}
 	}
 	if len(name) > sketchNameMaxLength {
-		return &cmderrors.CantCreateSketchError{Cause: errors.New(tr("sketch name too long (%[1]d characters). Maximum allowed length is %[2]d",
+		return &cmderrors.CantCreateSketchError{Cause: errors.New(i18n.Tr("sketch name too long (%[1]d characters). Maximum allowed length is %[2]d",
 			len(name),
 			sketchNameMaxLength))}
 	}
 	if !sketchNameValidationRegex.MatchString(name) {
-		return &cmderrors.CantCreateSketchError{Cause: errors.New(tr(`invalid sketch name "%[1]s": the first character must be alphanumeric or "_", the following ones can also contain "-" and ".". The last one cannot be ".".`,
+		return &cmderrors.CantCreateSketchError{Cause: errors.New(i18n.Tr(`invalid sketch name "%[1]s": the first character must be alphanumeric or "_", the following ones can also contain "-" and ".". The last one cannot be ".".`,
 			name))}
 	}
 	for _, invalid := range invalidNames {
 		if name == invalid {
-			return &cmderrors.CantCreateSketchError{Cause: errors.New(tr(`sketch name cannot be the reserved name "%[1]s"`, invalid))}
+			return &cmderrors.CantCreateSketchError{Cause: errors.New(i18n.Tr(`sketch name cannot be the reserved name "%[1]s"`, invalid))}
 		}
 	}
 	return nil
diff --git a/commands/service_upload.go b/commands/service_upload.go
index 6dcacf1d3e5..330decc3c5e 100644
--- a/commands/service_upload.go
+++ b/commands/service_upload.go
@@ -31,6 +31,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
 	properties "github.com/arduino/go-properties-orderedmap"
@@ -433,13 +434,13 @@ func runProgramAction(ctx context.Context, pme *packagemanager.Explorer,
 	if !burnBootloader {
 		importPath, sketchName, err := determineBuildPathAndSketchName(importFile, importDir, sk)
 		if err != nil {
-			return nil, &cmderrors.NotFoundError{Message: tr("Error finding build artifacts"), Cause: err}
+			return nil, &cmderrors.NotFoundError{Message: i18n.Tr("Error finding build artifacts"), Cause: err}
 		}
 		if !importPath.Exist() {
-			return nil, &cmderrors.NotFoundError{Message: tr("Compiled sketch not found in %s", importPath)}
+			return nil, &cmderrors.NotFoundError{Message: i18n.Tr("Compiled sketch not found in %s", importPath)}
 		}
 		if !importPath.IsDir() {
-			return nil, &cmderrors.NotFoundError{Message: tr("Expected compiled sketch in directory %s, but is a file instead", importPath)}
+			return nil, &cmderrors.NotFoundError{Message: i18n.Tr("Expected compiled sketch in directory %s, but is a file instead", importPath)}
 		}
 		uploadProperties.SetPath("build.path", importPath)
 		uploadProperties.Set("build.project_name", sketchName)
@@ -492,20 +493,20 @@ func runProgramAction(ctx context.Context, pme *packagemanager.Explorer,
 
 		// if touch is requested but port is not specified, print a warning
 		if touch && portToTouch == "" {
-			outStream.Write([]byte(fmt.Sprintln(tr("Skipping 1200-bps touch reset: no serial port selected!"))))
+			outStream.Write([]byte(fmt.Sprintln(i18n.Tr("Skipping 1200-bps touch reset: no serial port selected!"))))
 		}
 
 		cb := &serialutils.ResetProgressCallbacks{
 			TouchingPort: func(portAddress string) {
 				logrus.WithField("phase", "board reset").Infof("Performing 1200-bps touch reset on serial port %s", portAddress)
 				if verbose {
-					outStream.Write([]byte(fmt.Sprintln(tr("Performing 1200-bps touch reset on serial port %s", portAddress))))
+					outStream.Write([]byte(fmt.Sprintln(i18n.Tr("Performing 1200-bps touch reset on serial port %s", portAddress))))
 				}
 			},
 			WaitingForNewSerial: func() {
 				logrus.WithField("phase", "board reset").Info("Waiting for upload port...")
 				if verbose {
-					outStream.Write([]byte(fmt.Sprintln(tr("Waiting for upload port..."))))
+					outStream.Write([]byte(fmt.Sprintln(i18n.Tr("Waiting for upload port..."))))
 				}
 			},
 			BootloaderPortFound: func(portAddress string) {
@@ -516,9 +517,9 @@ func runProgramAction(ctx context.Context, pme *packagemanager.Explorer,
 				}
 				if verbose {
 					if portAddress != "" {
-						outStream.Write([]byte(fmt.Sprintln(tr("Upload port found on %s", portAddress))))
+						outStream.Write([]byte(fmt.Sprintln(i18n.Tr("Upload port found on %s", portAddress))))
 					} else {
-						outStream.Write([]byte(fmt.Sprintln(tr("No upload port found, using %s as fallback", actualPort.Address))))
+						outStream.Write([]byte(fmt.Sprintln(i18n.Tr("No upload port found, using %s as fallback", actualPort.Address))))
 					}
 				}
 			},
@@ -528,7 +529,7 @@ func runProgramAction(ctx context.Context, pme *packagemanager.Explorer,
 		}
 
 		if newPortAddress, err := serialutils.Reset(portToTouch, wait, dryRun, nil, cb); err != nil {
-			errStream.Write([]byte(fmt.Sprintln(tr("Cannot perform port reset: %s", err))))
+			errStream.Write([]byte(fmt.Sprintln(i18n.Tr("Cannot perform port reset: %s", err))))
 		} else {
 			if newPortAddress != "" {
 				actualPort.Address = newPortAddress
@@ -562,18 +563,18 @@ func runProgramAction(ctx context.Context, pme *packagemanager.Explorer,
 	toolEnv := pme.GetEnvVarsForSpawnedProcess()
 	if burnBootloader {
 		if err := runTool("erase.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil {
-			return nil, &cmderrors.FailedUploadError{Message: tr("Failed chip erase"), Cause: err}
+			return nil, &cmderrors.FailedUploadError{Message: i18n.Tr("Failed chip erase"), Cause: err}
 		}
 		if err := runTool("bootloader.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil {
-			return nil, &cmderrors.FailedUploadError{Message: tr("Failed to burn bootloader"), Cause: err}
+			return nil, &cmderrors.FailedUploadError{Message: i18n.Tr("Failed to burn bootloader"), Cause: err}
 		}
 	} else if programmer != nil {
 		if err := runTool("program.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil {
-			return nil, &cmderrors.FailedUploadError{Message: tr("Failed programming"), Cause: err}
+			return nil, &cmderrors.FailedUploadError{Message: i18n.Tr("Failed programming"), Cause: err}
 		}
 	} else {
 		if err := runTool("upload.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil {
-			return nil, &cmderrors.FailedUploadError{Message: tr("Failed uploading"), Cause: err}
+			return nil, &cmderrors.FailedUploadError{Message: i18n.Tr("Failed uploading"), Cause: err}
 		}
 	}
 
@@ -693,18 +694,18 @@ func detectUploadPort(
 func runTool(recipeID string, props *properties.Map, outStream, errStream io.Writer, verbose bool, dryRun bool, toolEnv []string) error {
 	recipe, ok := props.GetOk(recipeID)
 	if !ok {
-		return fmt.Errorf(tr("recipe not found '%s'"), recipeID)
+		return errors.New(i18n.Tr("recipe not found '%s'", recipeID))
 	}
 	if strings.TrimSpace(recipe) == "" {
 		return nil // Nothing to run
 	}
 	if props.IsPropertyMissingInExpandPropsInString("serial.port", recipe) || props.IsPropertyMissingInExpandPropsInString("serial.port.file", recipe) {
-		return fmt.Errorf(tr("no upload port provided"))
+		return errors.New(i18n.Tr("no upload port provided"))
 	}
 	cmdLine := props.ExpandPropsInString(recipe)
 	cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false)
 	if err != nil {
-		return fmt.Errorf(tr("invalid recipe '%[1]s': %[2]s"), recipe, err)
+		return errors.New(i18n.Tr("invalid recipe '%[1]s': %[2]s", recipe, err))
 	}
 
 	// Run Tool
@@ -717,18 +718,18 @@ func runTool(recipeID string, props *properties.Map, outStream, errStream io.Wri
 	}
 	cmd, err := paths.NewProcess(toolEnv, cmdArgs...)
 	if err != nil {
-		return fmt.Errorf(tr("cannot execute upload tool: %s"), err)
+		return errors.New(i18n.Tr("cannot execute upload tool: %s", err))
 	}
 
 	cmd.RedirectStdoutTo(outStream)
 	cmd.RedirectStderrTo(errStream)
 
 	if err := cmd.Start(); err != nil {
-		return fmt.Errorf(tr("cannot execute upload tool: %s"), err)
+		return errors.New(i18n.Tr("cannot execute upload tool: %s", err))
 	}
 
 	if err := cmd.Wait(); err != nil {
-		return fmt.Errorf(tr("uploading error: %s"), err)
+		return errors.New(i18n.Tr("uploading error: %s", err))
 	}
 
 	return nil
@@ -750,7 +751,7 @@ func determineBuildPathAndSketchName(importFile, importDir string, sk *sketch.Sk
 	// Case 1: importFile flag has been specified
 	if importFile != "" {
 		if importDir != "" {
-			return nil, "", fmt.Errorf(tr("%s and %s cannot be used together", "importFile", "importDir"))
+			return nil, "", errors.New(i18n.Tr("%s and %s cannot be used together", "importFile", "importDir"))
 		}
 
 		// We have a path like "path/to/my/build/SketchName.ino.bin". We are going to
@@ -760,7 +761,7 @@ func determineBuildPathAndSketchName(importFile, importDir string, sk *sketch.Sk
 
 		importFilePath := paths.New(importFile)
 		if !importFilePath.Exist() {
-			return nil, "", fmt.Errorf(tr("binary file not found in %s"), importFilePath)
+			return nil, "", errors.New(i18n.Tr("binary file not found in %s", importFilePath))
 		}
 		return importFilePath.Parent(), strings.TrimSuffix(importFilePath.Base(), importFilePath.Ext()), nil
 	}
@@ -775,14 +776,14 @@ func determineBuildPathAndSketchName(importFile, importDir string, sk *sketch.Sk
 		buildPath := paths.New(importDir)
 		sketchName, err := detectSketchNameFromBuildPath(buildPath)
 		if err != nil {
-			return nil, "", fmt.Errorf("%s: %w", tr("looking for build artifacts"), err)
+			return nil, "", fmt.Errorf("%s: %w", i18n.Tr("looking for build artifacts"), err)
 		}
 		return buildPath, sketchName, nil
 	}
 
 	// Case 3: nothing given...
 	if sk == nil {
-		return nil, "", errors.New(tr("no sketch or build directory/file specified"))
+		return nil, "", errors.New(i18n.Tr("no sketch or build directory/file specified"))
 	}
 
 	// Case 4: only sketch specified. In this case we use the generated build path
@@ -827,12 +828,12 @@ func detectSketchNameFromBuildPath(buildPath *paths.Path) (string, error) {
 		}
 
 		if candidateName != name {
-			return "", errors.New(tr("multiple build artifacts found: '%[1]s' and '%[2]s'", candidateFile, file))
+			return "", errors.New(i18n.Tr("multiple build artifacts found: '%[1]s' and '%[2]s'", candidateFile, file))
 		}
 	}
 
 	if candidateName == "" {
-		return "", errors.New(tr("could not find a valid build artifact"))
+		return "", errors.New(i18n.Tr("could not find a valid build artifact"))
 	}
 	return candidateName, nil
 }
diff --git a/internal/arduino/builder/archive_compiled_files.go b/internal/arduino/builder/archive_compiled_files.go
index dc43d82ac87..ed87225e2ff 100644
--- a/internal/arduino/builder/archive_compiled_files.go
+++ b/internal/arduino/builder/archive_compiled_files.go
@@ -16,6 +16,7 @@
 package builder
 
 import (
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 )
 
@@ -23,7 +24,7 @@ import (
 func (b *Builder) archiveCompiledFiles(archiveFilePath *paths.Path, objectFilesToArchive paths.PathList) (*paths.Path, error) {
 	if b.onlyUpdateCompilationDatabase {
 		if b.logger.Verbose() {
-			b.logger.Info(tr("Skipping archive creation of: %[1]s", archiveFilePath))
+			b.logger.Info(i18n.Tr("Skipping archive creation of: %[1]s", archiveFilePath))
 		}
 		return archiveFilePath, nil
 	}
@@ -46,7 +47,7 @@ func (b *Builder) archiveCompiledFiles(archiveFilePath *paths.Path, objectFilesT
 			}
 		} else {
 			if b.logger.Verbose() {
-				b.logger.Info(tr("Using previously compiled file: %[1]s", archiveFilePath))
+				b.logger.Info(i18n.Tr("Using previously compiled file: %[1]s", archiveFilePath))
 			}
 			return archiveFilePath, nil
 		}
diff --git a/internal/arduino/builder/build_options_manager.go b/internal/arduino/builder/build_options_manager.go
index 31f7d6ffc07..09f0afad815 100644
--- a/internal/arduino/builder/build_options_manager.go
+++ b/internal/arduino/builder/build_options_manager.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	properties "github.com/arduino/go-properties-orderedmap"
 )
@@ -107,10 +108,10 @@ func (b *Builder) wipeBuildPath() error {
 	// control when this should be printed.
 	// logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_BUILD_OPTIONS_CHANGED + constants.MSG_REBUILD_ALL)
 	if err := b.buildOptions.buildPath.RemoveAll(); err != nil {
-		return fmt.Errorf("%s: %w", tr("cleaning build path"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("cleaning build path"), err)
 	}
 	if err := b.buildOptions.buildPath.MkdirAll(); err != nil {
-		return fmt.Errorf("%s: %w", tr("cleaning build path"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("cleaning build path"), err)
 	}
 	return nil
 }
@@ -136,7 +137,7 @@ func (b *Builder) wipeBuildPathIfBuildOptionsChanged() error {
 
 	var prevOpts *properties.Map
 	if err := json.Unmarshal(buildOptionsJSONPrevious, &prevOpts); err != nil || prevOpts == nil {
-		b.logger.Info(tr("%[1]s invalid, rebuilding all", "build.options.json"))
+		b.logger.Info(i18n.Tr("%[1]s invalid, rebuilding all", "build.options.json"))
 		return b.wipeBuildPath()
 	}
 
diff --git a/internal/arduino/builder/builder.go b/internal/arduino/builder/builder.go
index 1727556b846..d5ab7b35135 100644
--- a/internal/arduino/builder/builder.go
+++ b/internal/arduino/builder/builder.go
@@ -34,6 +34,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/libraries"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
@@ -306,7 +307,7 @@ func (b *Builder) preprocess() error {
 	}
 	b.Progress.CompleteStep()
 
-	b.logIfVerbose(false, tr("Detecting libraries used..."))
+	b.logIfVerbose(false, i18n.Tr("Detecting libraries used..."))
 	err := b.libsDetector.FindIncludes(
 		b.ctx,
 		b.buildPath,
@@ -326,7 +327,7 @@ func (b *Builder) preprocess() error {
 	b.warnAboutArchIncompatibleLibraries(b.libsDetector.ImportedLibraries())
 	b.Progress.CompleteStep()
 
-	b.logIfVerbose(false, tr("Generating function prototypes..."))
+	b.logIfVerbose(false, i18n.Tr("Generating function prototypes..."))
 	if err := b.preprocessSketch(b.libsDetector.IncludeFolders()); err != nil {
 		return err
 	}
@@ -378,7 +379,7 @@ func (b *Builder) Build() error {
 
 // Build fixdoc
 func (b *Builder) build() error {
-	b.logIfVerbose(false, tr("Compiling sketch..."))
+	b.logIfVerbose(false, i18n.Tr("Compiling sketch..."))
 	if err := b.RunRecipe("recipe.hooks.sketch.prebuild", ".pattern", false); err != nil {
 		return err
 	}
@@ -394,7 +395,7 @@ func (b *Builder) build() error {
 	}
 	b.Progress.CompleteStep()
 
-	b.logIfVerbose(false, tr("Compiling libraries..."))
+	b.logIfVerbose(false, i18n.Tr("Compiling libraries..."))
 	if err := b.RunRecipe("recipe.hooks.libraries.prebuild", ".pattern", false); err != nil {
 		return err
 	}
@@ -415,7 +416,7 @@ func (b *Builder) build() error {
 	}
 	b.Progress.CompleteStep()
 
-	b.logIfVerbose(false, tr("Compiling core..."))
+	b.logIfVerbose(false, i18n.Tr("Compiling core..."))
 	if err := b.RunRecipe("recipe.hooks.core.prebuild", ".pattern", false); err != nil {
 		return err
 	}
@@ -431,7 +432,7 @@ func (b *Builder) build() error {
 	}
 	b.Progress.CompleteStep()
 
-	b.logIfVerbose(false, tr("Linking everything together..."))
+	b.logIfVerbose(false, i18n.Tr("Linking everything together..."))
 	if err := b.RunRecipe("recipe.hooks.linking.prelink", ".pattern", false); err != nil {
 		return err
 	}
@@ -481,7 +482,7 @@ func (b *Builder) build() error {
 func (b *Builder) prepareCommandForRecipe(buildProperties *properties.Map, recipe string, removeUnsetProperties bool) (*paths.Process, error) {
 	pattern := buildProperties.Get(recipe)
 	if pattern == "" {
-		return nil, fmt.Errorf(tr("%[1]s pattern is missing"), recipe)
+		return nil, errors.New(i18n.Tr("%[1]s pattern is missing", recipe))
 	}
 
 	commandLine := buildProperties.ExpandPropsInString(pattern)
diff --git a/internal/arduino/builder/compilation.go b/internal/arduino/builder/compilation.go
index 69fa1c7974b..d3a1459da25 100644
--- a/internal/arduino/builder/compilation.go
+++ b/internal/arduino/builder/compilation.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 )
 
@@ -177,9 +178,9 @@ func (b *Builder) compileFileWithRecipe(
 		}
 	} else if b.logger.Verbose() {
 		if objIsUpToDate {
-			b.logger.Info(tr("Using previously compiled file: %[1]s", objectFile))
+			b.logger.Info(i18n.Tr("Using previously compiled file: %[1]s", objectFile))
 		} else {
-			b.logger.Info(tr("Skipping compile of: %[1]s", objectFile))
+			b.logger.Info(i18n.Tr("Skipping compile of: %[1]s", objectFile))
 		}
 	}
 
diff --git a/internal/arduino/builder/core.go b/internal/arduino/builder/core.go
index 78bedc18d5f..f19169f8990 100644
--- a/internal/arduino/builder/core.go
+++ b/internal/arduino/builder/core.go
@@ -19,7 +19,6 @@ import (
 	"crypto/md5"
 	"encoding/hex"
 	"errors"
-	"fmt"
 	"os"
 	"strings"
 
@@ -27,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/builder/cpp"
 	"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
 	"github.com/arduino/arduino-cli/internal/buildcache"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 )
 
@@ -38,8 +38,8 @@ func (b *Builder) buildCore() error {
 
 	if b.coreBuildCachePath != nil {
 		if _, err := b.coreBuildCachePath.RelTo(b.buildPath); err != nil {
-			b.logger.Info(tr("Couldn't deeply cache core build: %[1]s", err))
-			b.logger.Info(tr("Running normal build of the core..."))
+			b.logger.Info(i18n.Tr("Couldn't deeply cache core build: %[1]s", err))
+			b.logger.Info(i18n.Tr("Running normal build of the core..."))
 			// TODO decide if we want to override this or not. (It's only used by the
 			// compileCore function).
 			b.coreBuildCachePath = nil
@@ -92,7 +92,7 @@ func (b *Builder) compileCore() (*paths.Path, paths.PathList, error) {
 		targetArchivedCore = b.coreBuildCachePath.Join(archivedCoreName, "core.a")
 
 		if _, err := buildcache.New(b.coreBuildCachePath).GetOrCreate(archivedCoreName); errors.Is(err, buildcache.CreateDirErr) {
-			return nil, nil, fmt.Errorf(tr("creating core cache folder: %s", err))
+			return nil, nil, errors.New(i18n.Tr("creating core cache folder: %s", err))
 		}
 
 		var canUseArchivedCore bool
@@ -113,7 +113,7 @@ func (b *Builder) compileCore() (*paths.Path, paths.PathList, error) {
 		if canUseArchivedCore {
 			// use archived core
 			if b.logger.Verbose() {
-				b.logger.Info(tr("Using precompiled core: %[1]s", targetArchivedCore))
+				b.logger.Info(i18n.Tr("Using precompiled core: %[1]s", targetArchivedCore))
 			}
 			return targetArchivedCore, variantObjectFiles, nil
 		}
@@ -138,13 +138,13 @@ func (b *Builder) compileCore() (*paths.Path, paths.PathList, error) {
 		err := archiveFile.CopyTo(targetArchivedCore)
 		if b.logger.Verbose() {
 			if err == nil {
-				b.logger.Info(tr("Archiving built core (caching) in: %[1]s", targetArchivedCore))
+				b.logger.Info(i18n.Tr("Archiving built core (caching) in: %[1]s", targetArchivedCore))
 			} else if os.IsNotExist(err) {
-				b.logger.Info(tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s",
+				b.logger.Info(i18n.Tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s",
 					b.actualPlatform,
 					"https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-build-the-corea-archive-file"))
 			} else {
-				b.logger.Info(tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err))
+				b.logger.Info(i18n.Tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err))
 			}
 		}
 	}
diff --git a/internal/arduino/builder/internal/compilation/database.go b/internal/arduino/builder/internal/compilation/database.go
index 9498b5a9e81..3d20d277fab 100644
--- a/internal/arduino/builder/internal/compilation/database.go
+++ b/internal/arduino/builder/internal/compilation/database.go
@@ -25,8 +25,6 @@ import (
 	"github.com/arduino/go-paths-helper"
 )
 
-var tr = i18n.Tr
-
 // Database keeps track of all the compile commands run by the builder
 type Database struct {
 	lock     sync.Mutex
@@ -66,10 +64,10 @@ func (db *Database) SaveToFile() {
 	db.lock.Lock()
 	defer db.lock.Unlock()
 	if jsonContents, err := json.MarshalIndent(db.contents, "", " "); err != nil {
-		fmt.Println(tr("Error serializing compilation database: %s", err))
+		fmt.Println(i18n.Tr("Error serializing compilation database: %s", err))
 		return
 	} else if err := db.file.WriteFile(jsonContents); err != nil {
-		fmt.Println(tr("Error writing compilation database: %s", err))
+		fmt.Println(i18n.Tr("Error writing compilation database: %s", err))
 	}
 }
 
@@ -81,7 +79,7 @@ func (db *Database) Add(target *paths.Path, command *paths.Process) {
 		// current directory otherwise
 		dir, err := os.Getwd()
 		if err != nil {
-			fmt.Println(tr("Error getting current directory for compilation database: %s", err))
+			fmt.Println(i18n.Tr("Error getting current directory for compilation database: %s", err))
 		}
 		commandDir = dir
 	}
diff --git a/internal/arduino/builder/internal/detector/detector.go b/internal/arduino/builder/internal/detector/detector.go
index 8f9a305cea4..17de9377833 100644
--- a/internal/arduino/builder/internal/detector/detector.go
+++ b/internal/arduino/builder/internal/detector/detector.go
@@ -42,8 +42,6 @@ import (
 	"github.com/arduino/go-properties-orderedmap"
 )
 
-var tr = i18n.Tr
-
 type libraryResolutionResult struct {
 	Library          *libraries.Library
 	NotUsedLibraries []*libraries.Library
@@ -90,9 +88,9 @@ func (l *SketchLibrariesDetector) resolveLibrary(header, platformArch string) *l
 	candidates := l.librariesResolver.AlternativesFor(header)
 
 	if l.logger.Verbose() {
-		l.logger.Info(tr("Alternatives for %[1]s: %[2]s", header, candidates))
+		l.logger.Info(i18n.Tr("Alternatives for %[1]s: %[2]s", header, candidates))
 		l.logger.Info(fmt.Sprintf("ResolveLibrary(%s)", header))
-		l.logger.Info(fmt.Sprintf("  -> %s: %s", tr("candidates"), candidates))
+		l.logger.Info(fmt.Sprintf("  -> %s: %s", i18n.Tr("candidates"), candidates))
 	}
 
 	if len(candidates) == 0 {
@@ -155,10 +153,10 @@ func (l *SketchLibrariesDetector) PrintUsedAndNotUsedLibraries(sketchError bool)
 		if len(libResResult.NotUsedLibraries) == 0 {
 			continue
 		}
-		res += fmt.Sprintln(tr(`Multiple libraries were found for "%[1]s"`, header))
-		res += fmt.Sprintln("  " + tr("Used: %[1]s", libResResult.Library.InstallDir))
+		res += fmt.Sprintln(i18n.Tr(`Multiple libraries were found for "%[1]s"`, header))
+		res += fmt.Sprintln("  " + i18n.Tr("Used: %[1]s", libResResult.Library.InstallDir))
 		for _, notUsedLibrary := range libResResult.NotUsedLibraries {
-			res += fmt.Sprintln("  " + tr("Not used: %[1]s", notUsedLibrary.InstallDir))
+			res += fmt.Sprintln("  " + i18n.Tr("Not used: %[1]s", notUsedLibrary.InstallDir))
 		}
 	}
 	res = strings.TrimSpace(res)
@@ -212,8 +210,8 @@ func (l *SketchLibrariesDetector) FindIncludes(
 		l.logger.Info(
 			fmt.Sprintf(
 				"%s: %s",
-				tr("An error occurred detecting libraries"),
-				tr("the compilation database may be incomplete or inaccurate"),
+				i18n.Tr("An error occurred detecting libraries"),
+				i18n.Tr("the compilation database may be incomplete or inaccurate"),
 			),
 		)
 		return nil
@@ -350,7 +348,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
 		if unchanged && cache.valid {
 			missingIncludeH = cache.Next().Include
 			if first && l.logger.Verbose() {
-				l.logger.Info(tr("Using cached library dependencies for file: %[1]s", sourcePath))
+				l.logger.Info(i18n.Tr("Using cached library dependencies for file: %[1]s", sourcePath))
 			}
 		} else {
 			preprocFirstResult, preprocErr = preprocessor.GCC(ctx, sourcePath, targetFilePath, includeFolders, buildProperties)
@@ -368,7 +366,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
 			} else {
 				missingIncludeH = IncludesFinderWithRegExp(string(preprocFirstResult.Stderr()))
 				if missingIncludeH == "" && l.logger.Verbose() {
-					l.logger.Info(tr("Error while detecting libraries included by %[1]s", sourcePath))
+					l.logger.Info(i18n.Tr("Error while detecting libraries included by %[1]s", sourcePath))
 				}
 			}
 		}
@@ -393,7 +391,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
 					// gcc does not reproduce that, there is something wrong.
 					// Returning an error here will cause the cache to be
 					// deleted, so hopefully the next compilation will succeed.
-					return errors.New(tr("Internal error in cache"))
+					return errors.New(i18n.Tr("Internal error in cache"))
 				}
 				l.diagnosticStore.Parse(result.Args(), result.Stderr())
 				l.logger.WriteStderr(result.Stderr())
@@ -413,7 +411,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
 		if library.Precompiled && library.PrecompiledWithSources {
 			// Fully precompiled libraries should have no dependencies to avoid ABI breakage
 			if l.logger.Verbose() {
-				l.logger.Info(tr("Skipping dependencies detection for precompiled library %[1]s", library.Name))
+				l.logger.Info(i18n.Tr("Skipping dependencies detection for precompiled library %[1]s", library.Name))
 			}
 		} else {
 			for _, sourceDir := range library.SourceDirs() {
@@ -461,16 +459,16 @@ func (l *SketchLibrariesDetector) failIfImportedLibraryIsWrong() error {
 	for _, library := range l.importedLibraries {
 		if !library.IsLegacy {
 			if library.InstallDir.Join("arch").IsDir() {
-				return errors.New(tr("%[1]s folder is no longer supported! See %[2]s for more information", "'arch'", "http://goo.gl/gfFJzU"))
+				return errors.New(i18n.Tr("%[1]s folder is no longer supported! See %[2]s for more information", "'arch'", "http://goo.gl/gfFJzU"))
 			}
 			for _, propName := range libraries.MandatoryProperties {
 				if !library.Properties.ContainsKey(propName) {
-					return errors.New(tr("Missing '%[1]s' from library in %[2]s", propName, library.InstallDir))
+					return errors.New(i18n.Tr("Missing '%[1]s' from library in %[2]s", propName, library.InstallDir))
 				}
 			}
 			if library.Layout == libraries.RecursiveLayout {
 				if library.UtilityDir != nil {
-					return errors.New(tr("Library can't use both '%[1]s' and '%[2]s' folders. Double check in '%[3]s'.", "src", "utility", library.InstallDir))
+					return errors.New(i18n.Tr("Library can't use both '%[1]s' and '%[2]s' folders. Double check in '%[3]s'.", "src", "utility", library.InstallDir))
 				}
 			}
 		}
diff --git a/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go b/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go
index 399ca34f742..deabc04c4f0 100644
--- a/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go
+++ b/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
 )
@@ -60,7 +61,7 @@ func PreprocessSketchWithArduinoPreprocessor(
 	arduiniPreprocessorProperties.SetPath("source_file", targetFile)
 	pattern := arduiniPreprocessorProperties.Get("pattern")
 	if pattern == "" {
-		return nil, errors.New(tr("arduino-preprocessor pattern is missing"))
+		return nil, errors.New(i18n.Tr("arduino-preprocessor pattern is missing"))
 	}
 
 	commandLine := arduiniPreprocessorProperties.ExpandPropsInString(pattern)
diff --git a/internal/arduino/builder/internal/preprocessor/ctags.go b/internal/arduino/builder/internal/preprocessor/ctags.go
index 73b60f80c49..fe36cfc89e5 100644
--- a/internal/arduino/builder/internal/preprocessor/ctags.go
+++ b/internal/arduino/builder/internal/preprocessor/ctags.go
@@ -33,8 +33,6 @@ import (
 	"github.com/arduino/go-properties-orderedmap"
 )
 
-var tr = i18n.Tr
-
 // DebugPreprocessor when set to true the CTags preprocessor will output debugging info to stdout
 // this is useful for unit-testing to provide more infos
 var DebugPreprocessor bool
@@ -68,8 +66,8 @@ func PreprocessSketchWithCtags(
 
 		// Do not bail out if we are generating the compile commands database
 		stderr.WriteString(fmt.Sprintf("%s: %s",
-			tr("An error occurred adding prototypes"),
-			tr("the compilation database may be incomplete or inaccurate")))
+			i18n.Tr("An error occurred adding prototypes"),
+			i18n.Tr("the compilation database may be incomplete or inaccurate")))
 		if err := sourceFile.CopyTo(ctagsTarget); err != nil {
 			return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err
 		}
@@ -191,7 +189,7 @@ func RunCTags(ctx context.Context, sourceFile *paths.Path, buildProperties *prop
 
 	pattern := ctagsBuildProperties.Get("pattern")
 	if pattern == "" {
-		return nil, nil, errors.New(tr("%s pattern is missing", "ctags"))
+		return nil, nil, errors.New(i18n.Tr("%s pattern is missing", "ctags"))
 	}
 
 	commandLine := ctagsBuildProperties.ExpandPropsInString(pattern)
diff --git a/internal/arduino/builder/internal/preprocessor/gcc.go b/internal/arduino/builder/internal/preprocessor/gcc.go
index f97426c2df8..bfcc9512e0c 100644
--- a/internal/arduino/builder/internal/preprocessor/gcc.go
+++ b/internal/arduino/builder/internal/preprocessor/gcc.go
@@ -23,6 +23,7 @@ import (
 
 	f "github.com/arduino/arduino-cli/internal/algorithms"
 	"github.com/arduino/arduino-cli/internal/arduino/builder/cpp"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
 )
@@ -58,7 +59,7 @@ func GCC(
 
 	pattern := gccBuildProperties.Get(gccPreprocRecipeProperty)
 	if pattern == "" {
-		return Result{}, errors.New(tr("%s pattern is missing", gccPreprocRecipeProperty))
+		return Result{}, errors.New(i18n.Tr("%s pattern is missing", gccPreprocRecipeProperty))
 	}
 
 	commandLine := gccBuildProperties.ExpandPropsInString(pattern)
diff --git a/internal/arduino/builder/libraries.go b/internal/arduino/builder/libraries.go
index e1df2fd64cd..f5648a09596 100644
--- a/internal/arduino/builder/libraries.go
+++ b/internal/arduino/builder/libraries.go
@@ -23,6 +23,7 @@ import (
 	f "github.com/arduino/arduino-cli/internal/algorithms"
 	"github.com/arduino/arduino-cli/internal/arduino/builder/cpp"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
 )
@@ -87,25 +88,25 @@ func (b *Builder) findExpectedPrecompiledLibFolder(
 		}
 	}
 
-	b.logger.Info(tr("Library %[1]s has been declared precompiled:", library.Name))
+	b.logger.Info(i18n.Tr("Library %[1]s has been declared precompiled:", library.Name))
 
 	// Try directory with full fpuSpecs first, if available
 	if len(fpuSpecs) > 0 {
 		fpuSpecs = strings.TrimRight(fpuSpecs, "-")
 		fullPrecompDir := library.SourceDir.Join(mcu).Join(fpuSpecs)
 		if fullPrecompDir.Exist() && directoryContainsFile(fullPrecompDir) {
-			b.logger.Info(tr("Using precompiled library in %[1]s", fullPrecompDir))
+			b.logger.Info(i18n.Tr("Using precompiled library in %[1]s", fullPrecompDir))
 			return fullPrecompDir
 		}
-		b.logger.Info(tr(`Precompiled library in "%[1]s" not found`, fullPrecompDir))
+		b.logger.Info(i18n.Tr(`Precompiled library in "%[1]s" not found`, fullPrecompDir))
 	}
 
 	precompDir := library.SourceDir.Join(mcu)
 	if precompDir.Exist() && directoryContainsFile(precompDir) {
-		b.logger.Info(tr("Using precompiled library in %[1]s", precompDir))
+		b.logger.Info(i18n.Tr("Using precompiled library in %[1]s", precompDir))
 		return precompDir
 	}
-	b.logger.Info(tr(`Precompiled library in "%[1]s" not found`, precompDir))
+	b.logger.Info(i18n.Tr(`Precompiled library in "%[1]s" not found`, precompDir))
 	return nil
 }
 
@@ -129,7 +130,7 @@ func (b *Builder) compileLibraries(libraries libraries.List, includes []string)
 
 func (b *Builder) compileLibrary(library *libraries.Library, includes []string) (paths.PathList, error) {
 	if b.logger.Verbose() {
-		b.logger.Info(tr(`Compiling library "%[1]s"`, library.Name))
+		b.logger.Info(i18n.Tr(`Compiling library "%[1]s"`, library.Name))
 	}
 	libraryBuildPath := b.librariesBuildPath.Join(library.DirName)
 
@@ -147,7 +148,7 @@ func (b *Builder) compileLibrary(library *libraries.Library, includes []string)
 		)
 
 		if !coreSupportPrecompiled {
-			b.logger.Info(tr("The platform does not support '%[1]s' for precompiled libraries.", "compiler.libraries.ldflags"))
+			b.logger.Info(i18n.Tr("The platform does not support '%[1]s' for precompiled libraries.", "compiler.libraries.ldflags"))
 		} else if precompiledPath != nil {
 			// Find all libraries in precompiledPath
 			libs, err := precompiledPath.ReadDir()
@@ -279,7 +280,7 @@ func (b *Builder) warnAboutArchIncompatibleLibraries(importedLibraries libraries
 	for _, importedLibrary := range importedLibraries {
 		if !importedLibrary.SupportsAnyArchitectureIn(archs...) {
 			b.logger.Info(
-				tr("WARNING: library %[1]s claims to run on %[2]s architecture(s) and may be incompatible with your current board which runs on %[3]s architecture(s).",
+				i18n.Tr("WARNING: library %[1]s claims to run on %[2]s architecture(s) and may be incompatible with your current board which runs on %[3]s architecture(s).",
 					importedLibrary.Name,
 					strings.Join(importedLibrary.Architectures, ", "),
 					strings.Join(archs, ", ")))
@@ -298,17 +299,17 @@ func (b *Builder) printUsedLibraries(importedLibraries libraries.List) {
 	for _, library := range importedLibraries {
 		legacy := ""
 		if library.IsLegacy {
-			legacy = tr("(legacy)")
+			legacy = i18n.Tr("(legacy)")
 		}
 		if library.Version.String() == "" {
 			b.logger.Info(
-				tr("Using library %[1]s in folder: %[2]s %[3]s",
+				i18n.Tr("Using library %[1]s in folder: %[2]s %[3]s",
 					library.Name,
 					library.InstallDir,
 					legacy))
 		} else {
 			b.logger.Info(
-				tr("Using library %[1]s at version %[2]s in folder: %[3]s %[4]s",
+				i18n.Tr("Using library %[1]s at version %[2]s in folder: %[3]s %[4]s",
 					library.Name,
 					library.Version,
 					library.InstallDir,
diff --git a/internal/arduino/builder/linker.go b/internal/arduino/builder/linker.go
index c991778336d..e7d91811890 100644
--- a/internal/arduino/builder/linker.go
+++ b/internal/arduino/builder/linker.go
@@ -19,6 +19,7 @@ import (
 	"strings"
 
 	f "github.com/arduino/arduino-cli/internal/algorithms"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 )
 
@@ -26,7 +27,7 @@ import (
 func (b *Builder) link() error {
 	if b.onlyUpdateCompilationDatabase {
 		if b.logger.Verbose() {
-			b.logger.Info(tr("Skip linking of final executable."))
+			b.logger.Info(i18n.Tr("Skip linking of final executable."))
 		}
 		return nil
 	}
diff --git a/internal/arduino/builder/recipe.go b/internal/arduino/builder/recipe.go
index 742b4484682..5e71010c32c 100644
--- a/internal/arduino/builder/recipe.go
+++ b/internal/arduino/builder/recipe.go
@@ -20,6 +20,7 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	properties "github.com/arduino/go-properties-orderedmap"
 	"github.com/sirupsen/logrus"
 )
@@ -44,7 +45,7 @@ func (b *Builder) RunRecipe(prefix, suffix string, skipIfOnlyUpdatingCompilation
 
 		if b.onlyUpdateCompilationDatabase && skipIfOnlyUpdatingCompilationDatabase {
 			if b.logger.Verbose() {
-				b.logger.Info(tr("Skipping: %[1]s", strings.Join(command.GetArgs(), " ")))
+				b.logger.Info(i18n.Tr("Skipping: %[1]s", strings.Join(command.GetArgs(), " ")))
 			}
 			return nil
 		}
diff --git a/internal/arduino/builder/sizer.go b/internal/arduino/builder/sizer.go
index 5814ba3ff4e..84cf8012a32 100644
--- a/internal/arduino/builder/sizer.go
+++ b/internal/arduino/builder/sizer.go
@@ -24,6 +24,7 @@ import (
 	"strconv"
 
 	"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-properties-orderedmap"
 )
@@ -75,7 +76,7 @@ func (b *Builder) size() error {
 func (b *Builder) checkSizeAdvanced() (ExecutablesFileSections, error) {
 	command, err := b.prepareCommandForRecipe(b.buildProperties, "recipe.advanced_size.pattern", false)
 	if err != nil {
-		return nil, errors.New(tr("Error while determining sketch size: %s", err))
+		return nil, errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 	}
 	if b.logger.Verbose() {
 		b.logger.Info(utils.PrintableCommand(command.GetArgs()))
@@ -84,10 +85,10 @@ func (b *Builder) checkSizeAdvanced() (ExecutablesFileSections, error) {
 	command.RedirectStdoutTo(out)
 	command.RedirectStderrTo(b.logger.Stderr())
 	if err := command.Start(); err != nil {
-		return nil, errors.New(tr("Error while determining sketch size: %s", err))
+		return nil, errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 	}
 	if err := command.Wait(); err != nil {
-		return nil, errors.New(tr("Error while determining sketch size: %s", err))
+		return nil, errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 	}
 
 	type AdvancedSizerResponse struct {
@@ -106,7 +107,7 @@ func (b *Builder) checkSizeAdvanced() (ExecutablesFileSections, error) {
 
 	var resp AdvancedSizerResponse
 	if err := json.Unmarshal(out.Bytes(), &resp); err != nil {
-		return nil, errors.New(tr("Error while determining sketch size: %s", err))
+		return nil, errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 	}
 
 	executableSectionsSize := resp.Sections
@@ -150,23 +151,23 @@ func (b *Builder) checkSize() (ExecutablesFileSections, error) {
 
 	textSize, dataSize, _, err := b.execSizeRecipe(properties)
 	if err != nil {
-		b.logger.Warn(tr("Couldn't determine program size"))
+		b.logger.Warn(i18n.Tr("Couldn't determine program size"))
 		return nil, nil
 	}
 
-	b.logger.Info(tr("Sketch uses %[1]s bytes (%[3]s%%) of program storage space. Maximum is %[2]s bytes.",
+	b.logger.Info(i18n.Tr("Sketch uses %[1]s bytes (%[3]s%%) of program storage space. Maximum is %[2]s bytes.",
 		strconv.Itoa(textSize),
 		strconv.Itoa(maxTextSize),
 		strconv.Itoa(textSize*100/maxTextSize)))
 	if dataSize >= 0 {
 		if maxDataSize > 0 {
-			b.logger.Info(tr("Global variables use %[1]s bytes (%[3]s%%) of dynamic memory, leaving %[4]s bytes for local variables. Maximum is %[2]s bytes.",
+			b.logger.Info(i18n.Tr("Global variables use %[1]s bytes (%[3]s%%) of dynamic memory, leaving %[4]s bytes for local variables. Maximum is %[2]s bytes.",
 				strconv.Itoa(dataSize),
 				strconv.Itoa(maxDataSize),
 				strconv.Itoa(dataSize*100/maxDataSize),
 				strconv.Itoa(maxDataSize-dataSize)))
 		} else {
-			b.logger.Info(tr("Global variables use %[1]s bytes of dynamic memory.", strconv.Itoa(dataSize)))
+			b.logger.Info(i18n.Tr("Global variables use %[1]s bytes of dynamic memory.", strconv.Itoa(dataSize)))
 		}
 	}
 
@@ -186,13 +187,13 @@ func (b *Builder) checkSize() (ExecutablesFileSections, error) {
 	}
 
 	if textSize > maxTextSize {
-		b.logger.Warn(tr("Sketch too big; see %[1]s for tips on reducing it.", "https://support.arduino.cc/hc/en-us/articles/360013825179"))
-		return executableSectionsSize, errors.New(tr("text section exceeds available space in board"))
+		b.logger.Warn(i18n.Tr("Sketch too big; see %[1]s for tips on reducing it.", "https://support.arduino.cc/hc/en-us/articles/360013825179"))
+		return executableSectionsSize, errors.New(i18n.Tr("text section exceeds available space in board"))
 	}
 
 	if maxDataSize > 0 && dataSize > maxDataSize {
-		b.logger.Warn(tr("Not enough memory; see %[1]s for tips on reducing your footprint.", "https://support.arduino.cc/hc/en-us/articles/360013825179"))
-		return executableSectionsSize, errors.New(tr("data section exceeds available space in board"))
+		b.logger.Warn(i18n.Tr("Not enough memory; see %[1]s for tips on reducing your footprint.", "https://support.arduino.cc/hc/en-us/articles/360013825179"))
+		return executableSectionsSize, errors.New(i18n.Tr("data section exceeds available space in board"))
 	}
 
 	if w := properties.Get("build.warn_data_percentage"); w != "" {
@@ -201,7 +202,7 @@ func (b *Builder) checkSize() (ExecutablesFileSections, error) {
 			return executableSectionsSize, err
 		}
 		if maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100 {
-			b.logger.Warn(tr("Low memory available, stability problems may occur."))
+			b.logger.Warn(i18n.Tr("Low memory available, stability problems may occur."))
 		}
 	}
 
@@ -211,7 +212,7 @@ func (b *Builder) checkSize() (ExecutablesFileSections, error) {
 func (b *Builder) execSizeRecipe(properties *properties.Map) (textSize int, dataSize int, eepromSize int, resErr error) {
 	command, err := b.prepareCommandForRecipe(properties, "recipe.size.pattern", false)
 	if err != nil {
-		resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err)
+		resErr = errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 		return
 	}
 	if b.logger.Verbose() {
@@ -221,11 +222,11 @@ func (b *Builder) execSizeRecipe(properties *properties.Map) (textSize int, data
 	command.RedirectStdoutTo(commandStdout)
 	command.RedirectStderrTo(b.logger.Stderr())
 	if err := command.Start(); err != nil {
-		resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err)
+		resErr = errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 		return
 	}
 	if err := command.Wait(); err != nil {
-		resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err)
+		resErr = errors.New(i18n.Tr("Error while determining sketch size: %s", err))
 		return
 	}
 
@@ -236,23 +237,23 @@ func (b *Builder) execSizeRecipe(properties *properties.Map) (textSize int, data
 
 	textSize, err = computeSize(properties.Get("recipe.size.regex"), out)
 	if err != nil {
-		resErr = fmt.Errorf(tr("Invalid size regexp: %s"), err)
+		resErr = errors.New(i18n.Tr("Invalid size regexp: %s", err))
 		return
 	}
 	if textSize == -1 {
-		resErr = errors.New(tr("Missing size regexp"))
+		resErr = errors.New(i18n.Tr("Missing size regexp"))
 		return
 	}
 
 	dataSize, err = computeSize(properties.Get("recipe.size.regex.data"), out)
 	if err != nil {
-		resErr = fmt.Errorf(tr("Invalid data size regexp: %s"), err)
+		resErr = errors.New(i18n.Tr("Invalid data size regexp: %s", err))
 		return
 	}
 
 	eepromSize, err = computeSize(properties.Get("recipe.size.regex.eeprom"), out)
 	if err != nil {
-		resErr = fmt.Errorf(tr("Invalid eeprom size regexp: %s"), err)
+		resErr = errors.New(i18n.Tr("Invalid eeprom size regexp: %s", err))
 		return
 	}
 
diff --git a/internal/arduino/builder/sketch.go b/internal/arduino/builder/sketch.go
index 7f058dc7d38..1dda735138f 100644
--- a/internal/arduino/builder/sketch.go
+++ b/internal/arduino/builder/sketch.go
@@ -33,7 +33,6 @@ import (
 
 var (
 	includesArduinoH = regexp.MustCompile(`(?m)^\s*#\s*include\s*[<\"]Arduino\.h[>\"]`)
-	tr               = i18n.Tr
 )
 
 // prepareSketchBuildPath copies the sketch source files in the build path.
@@ -41,7 +40,7 @@ var (
 // .cpp file still needs to be Arduino-preprocessed to compile).
 func (b *Builder) prepareSketchBuildPath() error {
 	if err := b.sketchBuildPath.MkdirAll(); err != nil {
-		return fmt.Errorf("%s: %w", tr("unable to create a folder to save the sketch"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("unable to create a folder to save the sketch"), err)
 	}
 
 	offset, mergedSource, err := b.sketchMergeSources(b.sourceOverrides)
@@ -72,14 +71,14 @@ func (b *Builder) sketchMergeSources(overrides map[string]string) (int, string,
 	getSource := func(f *paths.Path) (string, error) {
 		path, err := b.sketch.FullPath.RelTo(f)
 		if err != nil {
-			return "", fmt.Errorf("%s: %w", tr("unable to compute relative path to the sketch for the item"), err)
+			return "", fmt.Errorf("%s: %w", i18n.Tr("unable to compute relative path to the sketch for the item"), err)
 		}
 		if override, ok := overrides[path.String()]; ok {
 			return override, nil
 		}
 		data, err := f.ReadFile()
 		if err != nil {
-			return "", fmt.Errorf(tr("reading file %[1]s: %[2]s"), f, err)
+			return "", errors.New(i18n.Tr("reading file %[1]s: %[2]s", f, err))
 		}
 		return string(data), nil
 	}
@@ -116,13 +115,13 @@ func (b *Builder) sketchCopyAdditionalFiles(buildPath *paths.Path, overrides map
 	for _, file := range b.sketch.AdditionalFiles {
 		relpath, err := b.sketch.FullPath.RelTo(file)
 		if err != nil {
-			return fmt.Errorf("%s: %w", tr("unable to compute relative path to the sketch for the item"), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("unable to compute relative path to the sketch for the item"), err)
 		}
 
 		targetPath := buildPath.JoinPath(relpath)
 		// create the directory containing the target
 		if err = targetPath.Parent().MkdirAll(); err != nil {
-			return fmt.Errorf("%s: %w", tr("unable to create the folder containing the item"), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("unable to create the folder containing the item"), err)
 		}
 
 		var sourceBytes []byte
@@ -133,7 +132,7 @@ func (b *Builder) sketchCopyAdditionalFiles(buildPath *paths.Path, overrides map
 			// read the source file
 			s, err := file.ReadFile()
 			if err != nil {
-				return fmt.Errorf("%s: %w", tr("unable to read contents of the source item"), err)
+				return fmt.Errorf("%s: %w", i18n.Tr("unable to read contents of the source item"), err)
 			}
 			sourceBytes = s
 		}
@@ -143,7 +142,7 @@ func (b *Builder) sketchCopyAdditionalFiles(buildPath *paths.Path, overrides map
 
 		err = writeIfDifferent(sourceBytes, targetPath)
 		if err != nil {
-			return fmt.Errorf("%s: %w", tr("unable to write to destination file"), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("unable to write to destination file"), err)
 		}
 	}
 
@@ -160,7 +159,7 @@ func writeIfDifferent(source []byte, destPath *paths.Path) error {
 	// Read the destination file if it exists
 	existingBytes, err := destPath.ReadFile()
 	if err != nil {
-		return fmt.Errorf("%s: %w", tr("unable to read contents of the destination item"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("unable to read contents of the destination item"), err)
 	}
 
 	// Overwrite if contents are different
@@ -241,7 +240,7 @@ func (b *Builder) mergeSketchWithBootloader() error {
 	bootloaderPath := b.buildProperties.GetPath("runtime.platform.path").Join("bootloaders", bootloader)
 	if bootloaderPath.NotExist() {
 		if b.logger.Verbose() {
-			b.logger.Warn(tr("Bootloader file specified but missing: %[1]s", bootloaderPath))
+			b.logger.Warn(i18n.Tr("Bootloader file specified but missing: %[1]s", bootloaderPath))
 		}
 		return nil
 	}
diff --git a/internal/arduino/cores/board.go b/internal/arduino/cores/board.go
index 312a3b81e76..ed1aa9c68b5 100644
--- a/internal/arduino/cores/board.go
+++ b/internal/arduino/cores/board.go
@@ -16,10 +16,11 @@
 package cores
 
 import (
-	"fmt"
+	"errors"
 	"strings"
 	"sync"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-properties-orderedmap"
 )
 
@@ -139,14 +140,14 @@ func (b *Board) GetBuildProperties(fqbn *FQBN) (*properties.Map, error) {
 	// Check for residual invalid options...
 	for option, value := range config.AsMap() {
 		if option == "" {
-			return nil, fmt.Errorf(tr("invalid empty option found"))
+			return nil, errors.New(i18n.Tr("invalid empty option found"))
 		}
 		if _, ok := b.configOptions.GetOk(option); !ok {
-			return nil, fmt.Errorf(tr("invalid option '%s'"), option)
+			return nil, errors.New(i18n.Tr("invalid option '%s'", option))
 		}
 		optionsConf, ok := b.configOptionProperties[option+"="+value]
 		if !ok {
-			return nil, fmt.Errorf(tr("invalid value '%[1]s' for option '%[2]s'"), value, option)
+			return nil, errors.New(i18n.Tr("invalid value '%[1]s' for option '%[2]s'", value, option))
 		}
 		buildProperties.Merge(optionsConf)
 	}
@@ -162,7 +163,7 @@ func (b *Board) GetBuildProperties(fqbn *FQBN) (*properties.Map, error) {
 func (b *Board) GeneratePropertiesForConfiguration(config string) (*properties.Map, error) {
 	fqbn, err := ParseFQBN(b.String() + ":" + config)
 	if err != nil {
-		return nil, fmt.Errorf(tr("parsing fqbn: %s"), err)
+		return nil, errors.New(i18n.Tr("parsing fqbn: %s", err))
 	}
 	return b.GetBuildProperties(fqbn)
 }
diff --git a/internal/arduino/cores/cores.go b/internal/arduino/cores/cores.go
index 9be3c48f365..79464ed9b46 100644
--- a/internal/arduino/cores/cores.go
+++ b/internal/arduino/cores/cores.go
@@ -29,7 +29,6 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
 	"github.com/arduino/arduino-cli/internal/arduino/resources"
 	"github.com/arduino/arduino-cli/internal/arduino/utils"
-	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
 	properties "github.com/arduino/go-properties-orderedmap"
@@ -137,8 +136,6 @@ type BoardManifestID struct {
 	USB string `json:"-"`
 }
 
-var tr = i18n.Tr
-
 // HasUsbID returns true if the BoardManifes contains the specified USB id as
 // identification for this board. usbID should be in the format "0000:0000"
 func (bm *BoardManifest) HasUsbID(vid, pid string) bool {
diff --git a/internal/arduino/cores/fqbn.go b/internal/arduino/cores/fqbn.go
index 8c6ef74ea39..0db32f45cb0 100644
--- a/internal/arduino/cores/fqbn.go
+++ b/internal/arduino/cores/fqbn.go
@@ -16,10 +16,11 @@
 package cores
 
 import (
-	"fmt"
+	"errors"
 	"regexp"
 	"strings"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	properties "github.com/arduino/go-properties-orderedmap"
 )
 
@@ -46,7 +47,7 @@ func ParseFQBN(fqbnIn string) (*FQBN, error) {
 	// Split fqbn
 	fqbnParts := strings.Split(fqbnIn, ":")
 	if len(fqbnParts) < 3 || len(fqbnParts) > 4 {
-		return nil, fmt.Errorf("not an FQBN: %s", fqbnIn)
+		return nil, errors.New(i18n.Tr("not an FQBN: %s", fqbnIn))
 	}
 
 	fqbn := &FQBN{
@@ -56,33 +57,33 @@ func ParseFQBN(fqbnIn string) (*FQBN, error) {
 		Configs:      properties.NewMap(),
 	}
 	if fqbn.BoardID == "" {
-		return nil, fmt.Errorf(tr("empty board identifier"))
+		return nil, errors.New(i18n.Tr("empty board identifier"))
 	}
 	// Check if the fqbn contains invalid characters
 	fqbnValidationRegex := regexp.MustCompile(`^[a-zA-Z0-9_.-]*$`)
 	for i := 0; i < 3; i++ {
 		if !fqbnValidationRegex.MatchString(fqbnParts[i]) {
-			return nil, fmt.Errorf(tr("fqbn's field %s contains an invalid character"), fqbnParts[i])
+			return nil, errors.New(i18n.Tr("fqbn's field %s contains an invalid character", fqbnParts[i]))
 		}
 	}
 	if len(fqbnParts) > 3 {
 		for _, pair := range strings.Split(fqbnParts[3], ",") {
 			parts := strings.SplitN(pair, "=", 2)
 			if len(parts) != 2 {
-				return nil, fmt.Errorf(tr("invalid config option: %s"), pair)
+				return nil, errors.New(i18n.Tr("invalid config option: %s", pair))
 			}
 			k := strings.TrimSpace(parts[0])
 			v := strings.TrimSpace(parts[1])
 			if k == "" {
-				return nil, fmt.Errorf(tr("invalid config option: %s"), pair)
+				return nil, errors.New(i18n.Tr("invalid config option: %s", pair))
 			}
 			if !fqbnValidationRegex.MatchString(k) {
-				return nil, fmt.Errorf(tr("config key %s contains an invalid character"), k)
+				return nil, errors.New(i18n.Tr("config key %s contains an invalid character", k))
 			}
 			// The config value can also contain the = symbol
 			valueValidationRegex := regexp.MustCompile(`^[a-zA-Z0-9=_.-]*$`)
 			if !valueValidationRegex.MatchString(v) {
-				return nil, fmt.Errorf(tr("config value %s contains an invalid character"), v)
+				return nil, errors.New(i18n.Tr("config value %s contains an invalid character", v))
 			}
 			fqbn.Configs.Set(k, v)
 		}
diff --git a/internal/arduino/cores/packageindex/index.go b/internal/arduino/cores/packageindex/index.go
index 6cde8d1e90f..18e70ce524b 100644
--- a/internal/arduino/cores/packageindex/index.go
+++ b/internal/arduino/cores/packageindex/index.go
@@ -17,6 +17,7 @@ package packageindex
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
 
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
@@ -139,8 +140,6 @@ type indexHelp struct {
 	Online string `json:"online,omitempty"`
 }
 
-var tr = i18n.Tr
-
 // MergeIntoPackages converts the Index data into a cores.Packages and merge them
 // with the existing contents of the cores.Packages passed as parameter.
 func (index Index) MergeIntoPackages(outPackages cores.Packages) {
@@ -275,7 +274,7 @@ func (inPlatformRelease indexPlatformRelease) extractPlatformIn(outPackage *core
 
 	size, err := inPlatformRelease.Size.Int64()
 	if err != nil {
-		return fmt.Errorf(tr("invalid platform archive size: %s"), err)
+		return errors.New(i18n.Tr("invalid platform archive size: %s", err))
 	}
 	outPlatformRelease := outPlatform.GetOrCreateRelease(inPlatformRelease.Version)
 	outPlatformRelease.Name = inPlatformRelease.Name
diff --git a/internal/arduino/cores/packagemanager/download.go b/internal/arduino/cores/packagemanager/download.go
index ad82c9f1867..05cc0f70047 100644
--- a/internal/arduino/cores/packagemanager/download.go
+++ b/internal/arduino/cores/packagemanager/download.go
@@ -18,10 +18,10 @@ package packagemanager
 import (
 	"context"
 	"errors"
-	"fmt"
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	semver "go.bug.st/relaxed-semver"
 )
@@ -73,37 +73,37 @@ func (pme *Explorer) FindPlatformRelease(ref *PlatformReference) *cores.Platform
 func (pme *Explorer) FindPlatformReleaseDependencies(item *PlatformReference) (*cores.PlatformRelease, []*cores.ToolRelease, error) {
 	targetPackage, exists := pme.packages[item.Package]
 	if !exists {
-		return nil, nil, fmt.Errorf(tr("package %s not found"), item.Package)
+		return nil, nil, errors.New(i18n.Tr("package %s not found", item.Package))
 	}
 	platform, exists := targetPackage.Platforms[item.PlatformArchitecture]
 	if !exists {
-		return nil, nil, fmt.Errorf(tr("platform %[1]s not found in package %[2]s"), item.PlatformArchitecture, targetPackage.String())
+		return nil, nil, errors.New(i18n.Tr("platform %[1]s not found in package %[2]s", item.PlatformArchitecture, targetPackage))
 	}
 
 	var release *cores.PlatformRelease
 	if item.PlatformVersion != nil {
 		release = platform.FindReleaseWithVersion(item.PlatformVersion)
 		if release == nil {
-			return nil, nil, fmt.Errorf(tr("required version %[1]s not found for platform %[2]s"), item.PlatformVersion, platform.String())
+			return nil, nil, errors.New(i18n.Tr("required version %[1]s not found for platform %[2]s", item.PlatformVersion, platform))
 		}
 	} else {
 		release = platform.GetLatestCompatibleRelease()
 		if release == nil {
-			return nil, nil, fmt.Errorf(tr("platform is not available for your OS"))
+			return nil, nil, errors.New(i18n.Tr("platform is not available for your OS"))
 		}
 	}
 
 	// replaces "latest" with latest version too
 	toolDeps, err := pme.packages.GetPlatformReleaseToolDependencies(release)
 	if err != nil {
-		return nil, nil, fmt.Errorf(tr("getting tool dependencies for platform %[1]s: %[2]s"), release.String(), err)
+		return nil, nil, errors.New(i18n.Tr("getting tool dependencies for platform %[1]s: %[2]s", release, err))
 	}
 
 	// discovery dependencies differ from normal tool since we always want to use the latest
 	// available version for the platform package
 	discoveryDependencies, err := pme.packages.GetPlatformReleaseDiscoveryDependencies(release)
 	if err != nil {
-		return nil, nil, fmt.Errorf(tr("getting discovery dependencies for platform %[1]s: %[2]s"), release.String(), err)
+		return nil, nil, errors.New(i18n.Tr("getting discovery dependencies for platform %[1]s: %[2]s", release, err))
 	}
 	toolDeps = append(toolDeps, discoveryDependencies...)
 
@@ -111,7 +111,7 @@ func (pme *Explorer) FindPlatformReleaseDependencies(item *PlatformReference) (*
 	// available version for the platform package
 	monitorDependencies, err := pme.packages.GetPlatformReleaseMonitorDependencies(release)
 	if err != nil {
-		return nil, nil, fmt.Errorf(tr("getting monitor dependencies for platform %[1]s: %[2]s"), release.String(), err)
+		return nil, nil, errors.New(i18n.Tr("getting monitor dependencies for platform %[1]s: %[2]s", release, err))
 	}
 	toolDeps = append(toolDeps, monitorDependencies...)
 
@@ -124,8 +124,8 @@ func (pme *Explorer) DownloadToolRelease(ctx context.Context, tool *cores.ToolRe
 	resource := tool.GetCompatibleFlavour()
 	if resource == nil {
 		return &cmderrors.FailedDownloadError{
-			Message: tr("Error downloading tool %s", tool),
-			Cause:   errors.New(tr("no versions available for the current OS, try contacting %s", tool.Tool.Package.Email))}
+			Message: i18n.Tr("Error downloading tool %s", tool),
+			Cause:   errors.New(i18n.Tr("no versions available for the current OS, try contacting %s", tool.Tool.Package.Email))}
 	}
 	return resource.Download(ctx, pme.DownloadDir, pme.downloaderConfig, tool.String(), progressCB, "")
 }
diff --git a/internal/arduino/cores/packagemanager/install_uninstall.go b/internal/arduino/cores/packagemanager/install_uninstall.go
index 978072036c3..7fb9b44dc02 100644
--- a/internal/arduino/cores/packagemanager/install_uninstall.go
+++ b/internal/arduino/cores/packagemanager/install_uninstall.go
@@ -20,12 +20,12 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"runtime"
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
 	"github.com/arduino/arduino-cli/internal/arduino/cores/packageindex"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 )
@@ -42,7 +42,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
 	skipPreUninstall bool,
 ) (*cores.PlatformRelease, error) {
 	if platformRef.PlatformVersion != nil {
-		return nil, &cmderrors.InvalidArgumentError{Message: tr("Upgrade doesn't accept parameters with version")}
+		return nil, &cmderrors.InvalidArgumentError{Message: i18n.Tr("Upgrade doesn't accept parameters with version")}
 	}
 
 	// Search the latest version for all specified platforms
@@ -86,14 +86,14 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
 	for _, tool := range requiredTools {
 		if tool.IsInstalled() {
 			log.WithField("tool", tool).Warn("Tool already installed")
-			taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", tool), Completed: true})
+			taskCB(&rpc.TaskProgress{Name: i18n.Tr("Tool %s already installed", tool), Completed: true})
 		} else {
 			toolsToInstall = append(toolsToInstall, tool)
 		}
 	}
 
 	// Package download
-	taskCB(&rpc.TaskProgress{Name: tr("Downloading packages")})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Downloading packages")})
 	for _, tool := range toolsToInstall {
 		if err := pme.DownloadToolRelease(ctx, tool, downloadCB); err != nil {
 			return err
@@ -116,11 +116,11 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
 	if installed == nil {
 		// No version of this platform is installed
 		log.Info("Installing platform")
-		taskCB(&rpc.TaskProgress{Name: tr("Installing platform %s", platformRelease)})
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Installing platform %s", platformRelease)})
 	} else {
 		// A platform with a different version is already installed
 		log.Info("Replacing platform " + installed.String())
-		taskCB(&rpc.TaskProgress{Name: tr("Replacing platform %[1]s with %[2]s", installed, platformRelease)})
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Replacing platform %[1]s with %[2]s", installed, platformRelease)})
 		platformRef := &PlatformReference{
 			Package:              platformRelease.Platform.Package.Name,
 			PlatformArchitecture: platformRelease.Platform.Architecture,
@@ -133,14 +133,14 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
 		var err error
 		_, installedTools, err = pme.FindPlatformReleaseDependencies(platformRef)
 		if err != nil {
-			return &cmderrors.NotFoundError{Message: tr("Can't find dependencies for platform %s", platformRef), Cause: err}
+			return &cmderrors.NotFoundError{Message: i18n.Tr("Can't find dependencies for platform %s", platformRef), Cause: err}
 		}
 	}
 
 	// Install
 	if err := pme.InstallPlatform(platformRelease); err != nil {
 		log.WithError(err).Error("Cannot install platform")
-		return &cmderrors.FailedInstallError{Message: tr("Cannot install platform"), Cause: err}
+		return &cmderrors.FailedInstallError{Message: i18n.Tr("Cannot install platform"), Cause: err}
 	}
 
 	// If upgrading remove previous release
@@ -150,20 +150,20 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
 		// In case of error try to rollback
 		if uninstallErr != nil {
 			log.WithError(uninstallErr).Error("Error upgrading platform.")
-			taskCB(&rpc.TaskProgress{Message: tr("Error upgrading platform: %s", uninstallErr)})
+			taskCB(&rpc.TaskProgress{Message: i18n.Tr("Error upgrading platform: %s", uninstallErr)})
 
 			// Rollback
 			if err := pme.UninstallPlatform(platformRelease, taskCB, skipPreUninstall); err != nil {
 				log.WithError(err).Error("Error rolling-back changes.")
-				taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)})
+				taskCB(&rpc.TaskProgress{Message: i18n.Tr("Error rolling-back changes: %s", err)})
 			}
 
-			return &cmderrors.FailedInstallError{Message: tr("Cannot upgrade platform"), Cause: uninstallErr}
+			return &cmderrors.FailedInstallError{Message: i18n.Tr("Cannot upgrade platform"), Cause: uninstallErr}
 		}
 
 		// Uninstall unused tools
 		for _, tool := range installedTools {
-			taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
+			taskCB(&rpc.TaskProgress{Name: i18n.Tr("Uninstalling %s, tool is no more required", tool)})
 			if !pme.IsToolRequired(tool) {
 				pme.UninstallTool(tool, taskCB, skipPreUninstall)
 			}
@@ -174,24 +174,24 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
 	// Perform post install
 	if !skipPostInstall {
 		log.Info("Running post_install script")
-		taskCB(&rpc.TaskProgress{Message: tr("Configuring platform.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Configuring platform.")})
 		if !platformRelease.IsInstalled() {
-			return errors.New(tr("platform not installed"))
+			return errors.New(i18n.Tr("platform not installed"))
 		}
 		stdout, stderr, err := pme.RunPreOrPostScript(platformRelease.InstallDir, "post_install")
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
 		if err != nil {
-			taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure platform: %s", err), Completed: true})
+			taskCB(&rpc.TaskProgress{Message: i18n.Tr("WARNING cannot configure platform: %s", err), Completed: true})
 		}
 
 	} else {
 		log.Info("Skipping platform configuration.")
-		taskCB(&rpc.TaskProgress{Message: tr("Skipping platform configuration.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Skipping platform configuration.")})
 	}
 
 	log.Info("Platform installed")
-	taskCB(&rpc.TaskProgress{Message: tr("Platform %s installed", platformRelease), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("Platform %s installed", platformRelease), Completed: true})
 	return nil
 }
 
@@ -208,7 +208,7 @@ func (pme *Explorer) InstallPlatform(platformRelease *cores.PlatformRelease) err
 // InstallPlatformInDirectory installs a specific release of a platform in a specific directory.
 func (pme *Explorer) InstallPlatformInDirectory(platformRelease *cores.PlatformRelease, destDir *paths.Path) error {
 	if err := platformRelease.Resource.Install(pme.DownloadDir, pme.tempDir, destDir); err != nil {
-		return errors.New(tr("installing platform %[1]s: %[2]s", platformRelease, err))
+		return errors.New(i18n.Tr("installing platform %[1]s: %[2]s", platformRelease, err))
 	}
 	if d, err := destDir.Abs(); err == nil {
 		platformRelease.InstallDir = d
@@ -216,7 +216,7 @@ func (pme *Explorer) InstallPlatformInDirectory(platformRelease *cores.PlatformR
 		return err
 	}
 	if err := pme.cacheInstalledJSON(platformRelease); err != nil {
-		return errors.New(tr("creating installed.json in %[1]s: %[2]s", platformRelease.InstallDir, err))
+		return errors.New(i18n.Tr("creating installed.json in %[1]s: %[2]s", platformRelease.InstallDir, err))
 	}
 	return nil
 }
@@ -277,37 +277,37 @@ func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, t
 	log := pme.log.WithField("platform", platformRelease)
 
 	log.Info("Uninstalling platform")
-	taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s", platformRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Uninstalling %s", platformRelease)})
 
 	if platformRelease.InstallDir == nil {
-		err := fmt.Errorf(tr("platform not installed"))
+		err := errors.New(i18n.Tr("platform not installed"))
 		log.WithError(err).Error("Error uninstalling")
 		return &cmderrors.FailedUninstallError{Message: err.Error()}
 	}
 
 	// Safety measure
 	if !pme.IsManagedPlatformRelease(platformRelease) {
-		err := fmt.Errorf(tr("%s is not managed by package manager"), platformRelease)
+		err := errors.New(i18n.Tr("%s is not managed by package manager", platformRelease))
 		log.WithError(err).Error("Error uninstalling")
 		return &cmderrors.FailedUninstallError{Message: err.Error()}
 	}
 
 	if !skipPreUninstall {
 		log.Info("Running pre_uninstall script")
-		taskCB(&rpc.TaskProgress{Message: tr("Running pre_uninstall script.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Running pre_uninstall script.")})
 		stdout, stderr, err := pme.RunPreOrPostScript(platformRelease.InstallDir, "pre_uninstall")
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
 		if err != nil {
-			taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
+			taskCB(&rpc.TaskProgress{Message: i18n.Tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
 		}
 	} else {
 		log.Info("Skipping pre_uninstall script.")
-		taskCB(&rpc.TaskProgress{Message: tr("Skipping pre_uninstall script.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Skipping pre_uninstall script.")})
 	}
 
 	if err := platformRelease.InstallDir.RemoveAll(); err != nil {
-		err = fmt.Errorf(tr("removing platform files: %s"), err)
+		err = errors.New(i18n.Tr("removing platform files: %s", err))
 		log.WithError(err).Error("Error uninstalling")
 		return &cmderrors.FailedUninstallError{Message: err.Error()}
 	}
@@ -315,7 +315,7 @@ func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, t
 	platformRelease.InstallDir = nil
 
 	log.Info("Platform uninstalled")
-	taskCB(&rpc.TaskProgress{Message: tr("Platform %s uninstalled", platformRelease), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("Platform %s uninstalled", platformRelease), Completed: true})
 	return nil
 }
 
@@ -325,17 +325,18 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task
 
 	if toolRelease.IsInstalled() {
 		log.Warn("Tool already installed")
-		taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", toolRelease), Completed: true})
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Tool %s already installed", toolRelease), Completed: true})
 		return nil
 	}
 
 	log.Info("Installing tool")
-	taskCB(&rpc.TaskProgress{Name: tr("Installing %s", toolRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Installing %s", toolRelease)})
 
 	toolResource := toolRelease.GetCompatibleFlavour()
 	if toolResource == nil {
-		return fmt.Errorf(tr("no compatible version of %[1]s tools found for the current os, try contacting %[2]s"),
-			toolRelease.Tool.Name, toolRelease.Tool.Package.Email)
+		return errors.New(
+			i18n.Tr("no compatible version of %[1]s tools found for the current os, try contacting %[2]s",
+				toolRelease.Tool.Name, toolRelease.Tool.Package.Email))
 	}
 	destDir := pme.PackagesDir.Join(
 		toolRelease.Tool.Package.Name,
@@ -345,7 +346,7 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task
 	err := toolResource.Install(pme.DownloadDir, pme.tempDir, destDir)
 	if err != nil {
 		log.WithError(err).Warn("Cannot install tool")
-		return &cmderrors.FailedInstallError{Message: tr("Cannot install tool %s", toolRelease), Cause: err}
+		return &cmderrors.FailedInstallError{Message: i18n.Tr("Cannot install tool %s", toolRelease), Cause: err}
 	}
 	if d, err := destDir.Abs(); err == nil {
 		toolRelease.InstallDir = d
@@ -355,19 +356,19 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task
 	// Perform post install
 	if !skipPostInstall {
 		log.Info("Running tool post_install script")
-		taskCB(&rpc.TaskProgress{Message: tr("Configuring tool.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Configuring tool.")})
 		stdout, stderr, err := pme.RunPreOrPostScript(toolRelease.InstallDir, "post_install")
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout)})
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr)})
 		if err != nil {
-			taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure tool: %s", err)})
+			taskCB(&rpc.TaskProgress{Message: i18n.Tr("WARNING cannot configure tool: %s", err)})
 		}
 	} else {
 		log.Info("Skipping tool configuration.")
-		taskCB(&rpc.TaskProgress{Message: tr("Skipping tool configuration.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Skipping tool configuration.")})
 	}
 	log.Info("Tool installed")
-	taskCB(&rpc.TaskProgress{Message: tr("%s installed", toolRelease), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("%s installed", toolRelease), Completed: true})
 
 	return nil
 }
@@ -395,28 +396,28 @@ func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Ta
 	log.Info("Uninstalling tool")
 
 	if toolRelease.InstallDir == nil {
-		return fmt.Errorf(tr("tool not installed"))
+		return errors.New(i18n.Tr("tool not installed"))
 	}
 
 	// Safety measure
 	if !pme.IsManagedToolRelease(toolRelease) {
-		err := &cmderrors.FailedUninstallError{Message: tr("tool %s is not managed by package manager", toolRelease)}
+		err := &cmderrors.FailedUninstallError{Message: i18n.Tr("tool %s is not managed by package manager", toolRelease)}
 		log.WithError(err).Error("Error uninstalling")
 		return err
 	}
 
 	if !skipPreUninstall {
 		log.Info("Running pre_uninstall script")
-		taskCB(&rpc.TaskProgress{Message: tr("Running pre_uninstall script.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Running pre_uninstall script.")})
 		stdout, stderr, err := pme.RunPreOrPostScript(toolRelease.InstallDir, "pre_uninstall")
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
 		skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
 		if err != nil {
-			taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
+			taskCB(&rpc.TaskProgress{Message: i18n.Tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
 		}
 	} else {
 		log.Info("Skipping pre_uninstall script.")
-		taskCB(&rpc.TaskProgress{Message: tr("Skipping pre_uninstall script.")})
+		taskCB(&rpc.TaskProgress{Message: i18n.Tr("Skipping pre_uninstall script.")})
 	}
 
 	if err := toolRelease.InstallDir.RemoveAll(); err != nil {
@@ -428,7 +429,7 @@ func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Ta
 	toolRelease.InstallDir = nil
 
 	log.Info("Tool uninstalled")
-	taskCB(&rpc.TaskProgress{Message: tr("Tool %s uninstalled", toolRelease), Completed: true})
+	taskCB(&rpc.TaskProgress{Message: i18n.Tr("Tool %s uninstalled", toolRelease), Completed: true})
 	return nil
 }
 
diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go
index 8b42697a6e4..14e1d6df912 100644
--- a/internal/arduino/cores/packagemanager/loader.go
+++ b/internal/arduino/cores/packagemanager/loader.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	properties "github.com/arduino/go-properties-orderedmap"
 	semver "go.bug.st/relaxed-semver"
@@ -55,17 +56,17 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error {
 	var merr []error
 	pm.log.Infof("Loading hardware from: %s", path)
 	if err := path.ToAbs(); err != nil {
-		return append(merr, fmt.Errorf("%s: %w", tr("finding absolute path of %s", path), err))
+		return append(merr, fmt.Errorf("%s: %w", i18n.Tr("finding absolute path of %s", path), err))
 	}
 
 	if path.IsNotDir() {
-		return append(merr, errors.New(tr("%s is not a directory", path)))
+		return append(merr, errors.New(i18n.Tr("%s is not a directory", path)))
 	}
 
 	// Scan subdirs
 	packagersPaths, err := path.ReadDir()
 	if err != nil {
-		return append(merr, fmt.Errorf("%s: %w", tr("reading directory %s", path), err))
+		return append(merr, fmt.Errorf("%s: %w", i18n.Tr("reading directory %s", path), err))
 	}
 	packagersPaths.FilterOutHiddenFiles()
 	packagersPaths.FilterDirs()
@@ -94,7 +95,7 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error {
 		// Follow symlinks
 		err := packagerPath.FollowSymLink() // ex: .arduino15/packages/arduino/
 		if err != nil {
-			merr = append(merr, fmt.Errorf("%s: %w", tr("following symlink %s", path), err))
+			merr = append(merr, fmt.Errorf("%s: %w", i18n.Tr("following symlink %s", path), err))
 			continue
 		}
 
@@ -147,7 +148,7 @@ func (pm *Builder) loadPlatforms(targetPackage *cores.Package, packageDir *paths
 
 	platformsDirs, err := packageDir.ReadDir()
 	if err != nil {
-		return append(merr, fmt.Errorf("%s: %w", tr("reading directory %s", packageDir), err))
+		return append(merr, fmt.Errorf("%s: %w", i18n.Tr("reading directory %s", packageDir), err))
 	}
 
 	// A platform can only be inside a directory, thus we skip everything else.
@@ -175,7 +176,7 @@ func (pm *Builder) loadPlatforms(targetPackage *cores.Package, packageDir *paths
 func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture string, platformPath *paths.Path) error {
 	// This is not a platform
 	if platformPath.IsNotDir() {
-		return errors.New(tr("path is not a platform directory: %s", platformPath))
+		return errors.New(i18n.Tr("path is not a platform directory: %s", platformPath))
 	}
 
 	// There are two possible platform directory structures:
@@ -184,14 +185,14 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin
 	// We identify them by checking where is the bords.txt file
 	possibleBoardTxtPath := platformPath.Join("boards.txt")
 	if exist, err := possibleBoardTxtPath.ExistCheck(); err != nil {
-		return fmt.Errorf("%s: %w", tr("looking for boards.txt in %s", possibleBoardTxtPath), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("looking for boards.txt in %s", possibleBoardTxtPath), err)
 	} else if exist {
 		// case: ARCHITECTURE/boards.txt
 
 		platformTxtPath := platformPath.Join("platform.txt")
 		platformProperties, err := properties.SafeLoad(platformTxtPath.String())
 		if err != nil {
-			return fmt.Errorf("%s: %w", tr("loading platform.txt"), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("loading platform.txt"), err)
 		}
 
 		versionString := platformProperties.ExpandPropsInString(platformProperties.Get("version"))
@@ -204,7 +205,7 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin
 		platform.ManuallyInstalled = true
 		release := platform.GetOrCreateRelease(version)
 		if err := pm.loadPlatformRelease(release, platformPath); err != nil {
-			return fmt.Errorf("%s: %w", tr("loading platform release %s", release), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("loading platform release %s", release), err)
 		}
 		pm.log.WithField("platform", release).Infof("Loaded platform")
 
@@ -214,25 +215,25 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin
 
 		versionDirs, err := platformPath.ReadDir()
 		if err != nil {
-			return fmt.Errorf("%s: %w", tr("reading directory %s", platformPath), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("reading directory %s", platformPath), err)
 		}
 		versionDirs.FilterDirs()
 		versionDirs.FilterOutHiddenFiles()
 		for _, versionDir := range versionDirs {
 			if exist, err := versionDir.Join("boards.txt").ExistCheck(); err != nil {
-				return fmt.Errorf("%s: %w", tr("opening boards.txt"), err)
+				return fmt.Errorf("%s: %w", i18n.Tr("opening boards.txt"), err)
 			} else if !exist {
 				continue
 			}
 
 			version, err := semver.Parse(versionDir.Base())
 			if err != nil {
-				return fmt.Errorf("%s: %w", tr("invalid version directory %s", versionDir), err)
+				return fmt.Errorf("%s: %w", i18n.Tr("invalid version directory %s", versionDir), err)
 			}
 			platform := targetPackage.GetOrCreatePlatform(architecture)
 			release := platform.GetOrCreateRelease(version)
 			if err := pm.loadPlatformRelease(release, versionDir); err != nil {
-				return fmt.Errorf("%s: %w", tr("loading platform release %s", release), err)
+				return fmt.Errorf("%s: %w", i18n.Tr("loading platform release %s", release), err)
 			}
 			pm.log.WithField("platform", release).Infof("Loaded platform")
 		}
@@ -251,7 +252,7 @@ func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *pa
 	platform.Timestamps.AddFile(installedJSONPath)
 	if installedJSONPath.Exist() {
 		if _, err := pm.LoadPackageIndexFromFile(installedJSONPath); err != nil {
-			return fmt.Errorf(tr("loading %[1]s: %[2]s"), installedJSONPath, err)
+			return errors.New(i18n.Tr("loading %[1]s: %[2]s", installedJSONPath, err))
 		}
 	}
 
@@ -264,7 +265,7 @@ func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *pa
 	if p, err := properties.SafeLoadFromPath(platformTxtPath); err == nil {
 		platform.Properties.Merge(p)
 	} else {
-		return fmt.Errorf(tr("loading %[1]s: %[2]s"), platformTxtPath, err)
+		return errors.New(i18n.Tr("loading %[1]s: %[2]s", platformTxtPath, err))
 	}
 
 	platformTxtLocalPath := path.Join("platform.local.txt")
@@ -272,7 +273,7 @@ func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *pa
 	if p, err := properties.SafeLoadFromPath(platformTxtLocalPath); err == nil {
 		platform.Properties.Merge(p)
 	} else {
-		return fmt.Errorf(tr("loading %[1]s: %[2]s"), platformTxtLocalPath, err)
+		return errors.New(i18n.Tr("loading %[1]s: %[2]s", platformTxtLocalPath, err))
 	}
 
 	if platform.Properties.SubTree("pluggable_discovery").Size() > 0 || platform.Properties.SubTree("pluggable_monitor").Size() > 0 {
@@ -310,7 +311,7 @@ func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *pa
 	}
 
 	if err := pm.loadBoards(platform); err != nil {
-		return fmt.Errorf(tr("loading boards: %s"), err)
+		return errors.New(i18n.Tr("loading boards: %s", err))
 	}
 
 	if !platform.PluggableDiscoveryAware {
@@ -322,7 +323,7 @@ func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *pa
 	for protocol, ref := range platform.Properties.SubTree("pluggable_monitor.required").AsMap() {
 		split := strings.Split(ref, ":")
 		if len(split) != 2 {
-			return fmt.Errorf(tr("invalid pluggable monitor reference: %s"), ref)
+			return errors.New(i18n.Tr("invalid pluggable monitor reference: %s", ref))
 		}
 		pm.log.WithField("protocol", protocol).WithField("tool", ref).Info("Adding monitor tool")
 		platform.Monitors[protocol] = &cores.MonitorDependency{
@@ -416,7 +417,7 @@ func (pm *Builder) loadProgrammer(programmerProperties *properties.Map) *cores.P
 
 func (pm *Builder) loadBoards(platform *cores.PlatformRelease) error {
 	if platform.InstallDir == nil {
-		return fmt.Errorf(tr("platform not installed"))
+		return errors.New(i18n.Tr("platform not installed"))
 	}
 
 	boardsTxtPath := platform.InstallDir.Join("boards.txt")
@@ -578,7 +579,7 @@ func (pm *Builder) LoadToolsFromPackageDir(targetPackage *cores.Package, toolsPa
 
 	toolsPaths, err := toolsPath.ReadDir()
 	if err != nil {
-		return append(merr, fmt.Errorf("%s: %w", tr("reading directory %s", toolsPath), err))
+		return append(merr, fmt.Errorf("%s: %w", i18n.Tr("reading directory %s", toolsPath), err))
 	}
 	toolsPaths.FilterDirs()
 	toolsPaths.FilterOutHiddenFiles()
@@ -586,7 +587,7 @@ func (pm *Builder) LoadToolsFromPackageDir(targetPackage *cores.Package, toolsPa
 		name := toolPath.Base()
 		tool := targetPackage.GetOrCreateTool(name)
 		if err = pm.loadToolReleasesFromTool(tool, toolPath); err != nil {
-			merr = append(merr, fmt.Errorf("%s: %w", tr("loading tool release in %s", toolPath), err))
+			merr = append(merr, fmt.Errorf("%s: %w", i18n.Tr("loading tool release in %s", toolPath), err))
 		}
 	}
 	return merr
@@ -611,9 +612,9 @@ func (pm *Builder) loadToolReleasesFromTool(tool *cores.Tool, toolPath *paths.Pa
 
 func (pm *Builder) loadToolReleaseFromDirectory(tool *cores.Tool, version *semver.RelaxedVersion, toolReleasePath *paths.Path) error {
 	if absToolReleasePath, err := toolReleasePath.Abs(); err != nil {
-		return errors.New(tr("error opening %s", absToolReleasePath))
+		return errors.New(i18n.Tr("error opening %s", absToolReleasePath))
 	} else if !absToolReleasePath.IsDir() {
-		return errors.New(tr("%s is not a directory", absToolReleasePath))
+		return errors.New(i18n.Tr("%s is not a directory", absToolReleasePath))
 	} else {
 		toolRelease := tool.GetOrCreateRelease(version)
 		toolRelease.InstallDir = absToolReleasePath
@@ -640,11 +641,11 @@ func (pme *Explorer) LoadDiscoveries() []error {
 func (pme *Explorer) loadDiscovery(id string) error {
 	tool := pme.GetTool(id)
 	if tool == nil {
-		return errors.New(tr("discovery %s not found", id))
+		return errors.New(i18n.Tr("discovery %s not found", id))
 	}
 	toolRelease := tool.GetLatestInstalled()
 	if toolRelease == nil {
-		return errors.New(tr("discovery %s not installed", id))
+		return errors.New(i18n.Tr("discovery %s not installed", id))
 	}
 	discoveryPath := toolRelease.InstallDir.Join(tool.Name).String()
 	pme.discoveryManager.Add(id, discoveryPath)
@@ -708,7 +709,7 @@ func (pme *Explorer) loadDiscoveries(release *cores.PlatformRelease) []error {
 	for discoveryID, props := range discoveryIDs {
 		pattern, ok := props.GetOk("pattern")
 		if !ok {
-			merr = append(merr, errors.New(tr("can't find pattern for discovery with id %s", discoveryID)))
+			merr = append(merr, errors.New(i18n.Tr("can't find pattern for discovery with id %s", discoveryID)))
 			continue
 		}
 		configuration := release.Properties.Clone()
diff --git a/internal/arduino/cores/packagemanager/package_manager.go b/internal/arduino/cores/packagemanager/package_manager.go
index ffe278a6205..2821b23ddb4 100644
--- a/internal/arduino/cores/packagemanager/package_manager.go
+++ b/internal/arduino/cores/packagemanager/package_manager.go
@@ -17,7 +17,6 @@ package packagemanager
 
 import (
 	"errors"
-	"fmt"
 	"net/url"
 	"os"
 	"path"
@@ -74,8 +73,6 @@ type Builder PackageManager
 // job is completed.
 type Explorer PackageManager
 
-var tr = i18n.Tr
-
 // NewBuilder returns a new Builder
 func NewBuilder(indexDir, packagesDir, userPackagesDir, downloadDir, tempDir *paths.Path, userAgent string, downloaderConfig downloader.Config) *Builder {
 	return &Builder{
@@ -295,7 +292,7 @@ func (pme *Explorer) FindBoardsWithID(id string) []*cores.Board {
 func (pme *Explorer) FindBoardWithFQBN(fqbnIn string) (*cores.Board, error) {
 	fqbn, err := cores.ParseFQBN(fqbnIn)
 	if err != nil {
-		return nil, fmt.Errorf(tr("parsing fqbn: %s"), err)
+		return nil, errors.New(i18n.Tr("parsing fqbn: %s", err))
 	}
 
 	_, _, board, _, _, err := pme.ResolveFQBN(fqbn)
@@ -329,32 +326,32 @@ func (pme *Explorer) ResolveFQBN(fqbn *cores.FQBN) (
 	targetPackage := pme.packages[fqbn.Package]
 	if targetPackage == nil {
 		return nil, nil, nil, nil, nil,
-			fmt.Errorf(tr("unknown package %s"), fqbn.Package)
+			errors.New(i18n.Tr("unknown package %s", fqbn.Package))
 	}
 
 	// Find platform
 	platform := targetPackage.Platforms[fqbn.PlatformArch]
 	if platform == nil {
 		return targetPackage, nil, nil, nil, nil,
-			fmt.Errorf(tr("unknown platform %s:%s"), targetPackage, fqbn.PlatformArch)
+			errors.New(i18n.Tr("unknown platform %s:%s", targetPackage, fqbn.PlatformArch))
 	}
 	boardPlatformRelease := pme.GetInstalledPlatformRelease(platform)
 	if boardPlatformRelease == nil {
 		return targetPackage, nil, nil, nil, nil,
-			fmt.Errorf(tr("platform %s is not installed"), platform)
+			errors.New(i18n.Tr("platform %s is not installed", platform))
 	}
 
 	// Find board
 	board := boardPlatformRelease.Boards[fqbn.BoardID]
 	if board == nil {
 		return targetPackage, boardPlatformRelease, nil, nil, nil,
-			fmt.Errorf(tr("board %s not found"), fqbn.StringWithoutConfig())
+			errors.New(i18n.Tr("board %s not found", fqbn.StringWithoutConfig()))
 	}
 
 	boardBuildProperties, err := board.GetBuildProperties(fqbn)
 	if err != nil {
 		return targetPackage, boardPlatformRelease, board, nil, nil,
-			fmt.Errorf(tr("getting build properties for board %[1]s: %[2]s"), board, err)
+			errors.New(i18n.Tr("getting build properties for board %[1]s: %[2]s", board, err))
 	}
 
 	// Determine the platform used for the build and the variant (in case the board refers
@@ -443,7 +440,8 @@ func (pme *Explorer) determineReferencedPlatformRelease(boardBuildProperties *pr
 	// core and variant cannot refer to two different platforms
 	if referredCore != "" && referredVariant != "" && referredCore != referredVariant {
 		return "", nil, "", nil,
-			fmt.Errorf(tr("'build.core' and 'build.variant' refer to different platforms: %[1]s and %[2]s"), referredCore+":"+core, referredVariant+":"+variant)
+			errors.New(i18n.Tr("'build.core' and 'build.variant' refer to different platforms: %[1]s and %[2]s",
+				referredCore+":"+core, referredVariant+":"+variant))
 	}
 
 	// extract the referred platform
@@ -456,17 +454,17 @@ func (pme *Explorer) determineReferencedPlatformRelease(boardBuildProperties *pr
 		referredPackage := pme.packages[referredPackageName]
 		if referredPackage == nil {
 			return "", nil, "", nil,
-				fmt.Errorf(tr("missing package %[1]s referenced by board %[2]s"), referredPackageName, fqbn)
+				errors.New(i18n.Tr("missing package %[1]s referenced by board %[2]s", referredPackageName, fqbn))
 		}
 		referredPlatform := referredPackage.Platforms[fqbn.PlatformArch]
 		if referredPlatform == nil {
 			return "", nil, "", nil,
-				fmt.Errorf(tr("missing platform %[1]s:%[2]s referenced by board %[3]s"), referredPackageName, fqbn.PlatformArch, fqbn)
+				errors.New(i18n.Tr("missing platform %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.PlatformArch, fqbn))
 		}
 		referredPlatformRelease = pme.GetInstalledPlatformRelease(referredPlatform)
 		if referredPlatformRelease == nil {
 			return "", nil, "", nil,
-				fmt.Errorf(tr("missing platform release %[1]s:%[2]s referenced by board %[3]s"), referredPackageName, fqbn.PlatformArch, fqbn)
+				errors.New(i18n.Tr("missing platform release %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.PlatformArch, fqbn))
 		}
 	}
 
@@ -495,7 +493,7 @@ func (pmb *Builder) LoadPackageIndex(URL *url.URL) error {
 	indexPath := pmb.IndexDir.Join(indexFileName)
 	index, err := packageindex.LoadIndex(indexPath)
 	if err != nil {
-		return fmt.Errorf(tr("loading json index file %[1]s: %[2]s"), indexPath, err)
+		return errors.New(i18n.Tr("loading json index file %[1]s: %[2]s", indexPath, err))
 	}
 
 	for _, p := range index.Packages {
@@ -510,7 +508,7 @@ func (pmb *Builder) LoadPackageIndex(URL *url.URL) error {
 func (pmb *Builder) LoadPackageIndexFromFile(indexPath *paths.Path) (*packageindex.Index, error) {
 	index, err := packageindex.LoadIndex(indexPath)
 	if err != nil {
-		return nil, fmt.Errorf(tr("loading json index file %[1]s: %[2]s"), indexPath, err)
+		return nil, errors.New(i18n.Tr("loading json index file %[1]s: %[2]s", indexPath, err))
 	}
 
 	index.MergeIntoPackages(pmb.packages)
@@ -524,7 +522,7 @@ func (pme *Explorer) Package(name string) *PackageActions {
 	var err error
 	thePackage := pme.packages[name]
 	if thePackage == nil {
-		err = fmt.Errorf(tr("package '%s' not found"), name)
+		err = errors.New(i18n.Tr("package '%s' not found", name))
 	}
 	return &PackageActions{
 		aPackage:     thePackage,
@@ -550,7 +548,7 @@ func (pa *PackageActions) Tool(name string) *ToolActions {
 		tool = pa.aPackage.Tools[name]
 
 		if tool == nil {
-			err = fmt.Errorf(tr("tool '%[1]s' not found in package '%[2]s'"), name, pa.aPackage.Name)
+			err = errors.New(i18n.Tr("tool '%[1]s' not found in package '%[2]s'", name, pa.aPackage.Name))
 		}
 	}
 	return &ToolActions{
@@ -600,7 +598,7 @@ func (ta *ToolActions) Release(version *semver.RelaxedVersion) *ToolReleaseActio
 	}
 	release := ta.tool.FindReleaseWithRelaxedVersion(version)
 	if release == nil {
-		return &ToolReleaseActions{forwardError: fmt.Errorf(tr("release %[1]s not found for tool %[2]s"), version, ta.tool.String())}
+		return &ToolReleaseActions{forwardError: errors.New(i18n.Tr("release %[1]s not found for tool %[2]s", version, ta.tool))}
 	}
 	return &ToolReleaseActions{release: release}
 }
@@ -729,7 +727,7 @@ func (pme *Explorer) FindToolsRequiredFromPlatformRelease(platform *cores.Platfo
 		pme.log.WithField("tool", toolDep).Debugf("Required tool")
 		tool := pme.FindToolDependency(toolDep)
 		if tool == nil {
-			return nil, fmt.Errorf(tr("tool release not found: %s"), toolDep)
+			return nil, errors.New(i18n.Tr("tool release not found: %s", toolDep))
 		}
 		requiredTools = append(requiredTools, tool)
 		delete(foundTools, tool.Tool.Name)
@@ -740,7 +738,7 @@ func (pme *Explorer) FindToolsRequiredFromPlatformRelease(platform *cores.Platfo
 		pme.log.WithField("discovery", discoveryDep).Infof("Required discovery")
 		tool := pme.FindDiscoveryDependency(discoveryDep)
 		if tool == nil {
-			return nil, fmt.Errorf(tr("discovery release not found: %s"), discoveryDep)
+			return nil, errors.New(i18n.Tr("discovery release not found: %s", discoveryDep))
 		}
 		requiredTools = append(requiredTools, tool)
 		delete(foundTools, tool.Tool.Name)
@@ -751,7 +749,7 @@ func (pme *Explorer) FindToolsRequiredFromPlatformRelease(platform *cores.Platfo
 		pme.log.WithField("monitor", monitorDep).Infof("Required monitor")
 		tool := pme.FindMonitorDependency(monitorDep)
 		if tool == nil {
-			return nil, fmt.Errorf(tr("monitor release not found: %s"), monitorDep)
+			return nil, errors.New(i18n.Tr("monitor release not found: %s", monitorDep))
 		}
 		requiredTools = append(requiredTools, tool)
 		delete(foundTools, tool.Tool.Name)
@@ -835,7 +833,7 @@ func (pme *Explorer) FindToolsRequiredForBuild(platform, buildPlatform *cores.Pl
 		pme.log.WithField("tool", toolDep).Debugf("Required tool")
 		tool := pme.FindToolDependency(toolDep)
 		if tool == nil {
-			return nil, fmt.Errorf(tr("tool release not found: %s"), toolDep)
+			return nil, errors.New(i18n.Tr("tool release not found: %s", toolDep))
 		}
 		requiredTools = append(requiredTools, tool)
 		delete(allToolsAlternatives, tool.Tool.Name)
diff --git a/internal/arduino/cores/packagemanager/profiles.go b/internal/arduino/cores/packagemanager/profiles.go
index 5c7b4a58a16..f4635950785 100644
--- a/internal/arduino/cores/packagemanager/profiles.go
+++ b/internal/arduino/cores/packagemanager/profiles.go
@@ -17,6 +17,7 @@ package packagemanager
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net/url"
 
@@ -26,6 +27,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/resources"
 	"github.com/arduino/arduino-cli/internal/arduino/sketch"
 	"github.com/arduino/arduino-cli/internal/cli/configuration"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -42,7 +44,7 @@ func (pmb *Builder) LoadHardwareForProfile(ctx context.Context, p *sketch.Profil
 	indexURLs := map[string]*url.URL{}
 	for _, platformRef := range p.Platforms {
 		if platformRelease, err := pmb.loadProfilePlatform(ctx, platformRef, installMissing, downloadCB, taskCB, settings); err != nil {
-			merr = append(merr, fmt.Errorf("%s: %w", tr("loading required platform %s", platformRef), err))
+			merr = append(merr, fmt.Errorf("%s: %w", i18n.Tr("loading required platform %s", platformRef), err))
 			logrus.WithField("platform", platformRef).WithError(err).Debugf("Error loading platform for profile")
 		} else {
 			platformReleases = append(platformReleases, platformRelease)
@@ -58,7 +60,7 @@ func (pmb *Builder) LoadHardwareForProfile(ctx context.Context, p *sketch.Profil
 		for _, toolDep := range platformRelease.ToolDependencies {
 			indexURL := indexURLs[toolDep.ToolPackager]
 			if err := pmb.loadProfileTool(ctx, toolDep, indexURL, installMissing, downloadCB, taskCB, settings); err != nil {
-				merr = append(merr, fmt.Errorf("%s: %w", tr("loading required tool %s", toolDep), err))
+				merr = append(merr, fmt.Errorf("%s: %w", i18n.Tr("loading required tool %s", toolDep), err))
 				logrus.WithField("tool", toolDep).WithField("index_url", indexURL).WithError(err).Debugf("Error loading tool for profile")
 			} else {
 				logrus.WithField("tool", toolDep).WithField("index_url", indexURL).Debugf("Loaded tool for profile")
@@ -96,7 +98,7 @@ func (pmb *Builder) installMissingProfilePlatform(ctx context.Context, platformR
 	defer tmp.RemoveAll()
 
 	// Download the main index and parse it
-	taskCB(&rpc.TaskProgress{Name: tr("Downloading platform %s", platformRef)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Downloading platform %s", platformRef)})
 	defaultIndexURL, _ := url.Parse(globals.DefaultIndexURL)
 	indexesToDownload := []*url.URL{defaultIndexURL}
 	if platformRef.PlatformIndexURL != nil {
@@ -105,12 +107,12 @@ func (pmb *Builder) installMissingProfilePlatform(ctx context.Context, platformR
 	for _, indexURL := range indexesToDownload {
 		indexResource := resources.IndexResource{URL: indexURL}
 		if err := indexResource.Download(ctx, tmpPmb.IndexDir, downloadCB, pmb.downloaderConfig); err != nil {
-			taskCB(&rpc.TaskProgress{Name: tr("Error downloading %s", indexURL)})
-			return &cmderrors.FailedDownloadError{Message: tr("Error downloading %s", indexURL), Cause: err}
+			taskCB(&rpc.TaskProgress{Name: i18n.Tr("Error downloading %s", indexURL)})
+			return &cmderrors.FailedDownloadError{Message: i18n.Tr("Error downloading %s", indexURL), Cause: err}
 		}
 		if err := tmpPmb.LoadPackageIndex(indexURL); err != nil {
-			taskCB(&rpc.TaskProgress{Name: tr("Error loading index %s", indexURL)})
-			return &cmderrors.FailedInstallError{Message: tr("Error loading index %s", indexURL), Cause: err}
+			taskCB(&rpc.TaskProgress{Name: i18n.Tr("Error loading index %s", indexURL)})
+			return &cmderrors.FailedInstallError{Message: i18n.Tr("Error loading index %s", indexURL), Cause: err}
 		}
 	}
 
@@ -123,16 +125,16 @@ func (pmb *Builder) installMissingProfilePlatform(ctx context.Context, platformR
 	defer tmpRelease()
 
 	if err := tmpPme.DownloadPlatformRelease(ctx, tmpPlatformRelease, downloadCB); err != nil {
-		taskCB(&rpc.TaskProgress{Name: tr("Error downloading platform %s", tmpPlatformRelease)})
-		return &cmderrors.FailedInstallError{Message: tr("Error downloading platform %s", tmpPlatformRelease), Cause: err}
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Error downloading platform %s", tmpPlatformRelease)})
+		return &cmderrors.FailedInstallError{Message: i18n.Tr("Error downloading platform %s", tmpPlatformRelease), Cause: err}
 	}
 	taskCB(&rpc.TaskProgress{Completed: true})
 
 	// Perform install
-	taskCB(&rpc.TaskProgress{Name: tr("Installing platform %s", tmpPlatformRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Installing platform %s", tmpPlatformRelease)})
 	if err := tmpPme.InstallPlatformInDirectory(tmpPlatformRelease, destDir); err != nil {
-		taskCB(&rpc.TaskProgress{Name: tr("Error installing platform %s", tmpPlatformRelease)})
-		return &cmderrors.FailedInstallError{Message: tr("Error installing platform %s", tmpPlatformRelease), Cause: err}
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Error installing platform %s", tmpPlatformRelease)})
+		return &cmderrors.FailedInstallError{Message: i18n.Tr("Error installing platform %s", tmpPlatformRelease), Cause: err}
 	}
 	taskCB(&rpc.TaskProgress{Completed: true})
 	return nil
@@ -149,7 +151,7 @@ func (pmb *Builder) loadProfileTool(ctx context.Context, toolRef *cores.ToolDepe
 		// Try installing the missing tool
 		toolRelease := tool.GetOrCreateRelease(toolRef.ToolVersion)
 		if toolRelease == nil {
-			return &cmderrors.InvalidVersionError{Cause: fmt.Errorf(tr("version %s not found", toolRef.ToolVersion))}
+			return &cmderrors.InvalidVersionError{Cause: errors.New(i18n.Tr("version %s not found", toolRef.ToolVersion))}
 		}
 		if err := pmb.installMissingProfileTool(ctx, toolRelease, destDir, downloadCB, taskCB); err != nil {
 			return err
@@ -170,20 +172,20 @@ func (pmb *Builder) installMissingProfileTool(ctx context.Context, toolRelease *
 	// Download the tool
 	toolResource := toolRelease.GetCompatibleFlavour()
 	if toolResource == nil {
-		return &cmderrors.InvalidVersionError{Cause: fmt.Errorf(tr("version %s not available for this operating system", toolRelease))}
+		return &cmderrors.InvalidVersionError{Cause: errors.New(i18n.Tr("version %s not available for this operating system", toolRelease))}
 	}
-	taskCB(&rpc.TaskProgress{Name: tr("Downloading tool %s", toolRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Downloading tool %s", toolRelease)})
 	if err := toolResource.Download(ctx, pmb.DownloadDir, pmb.downloaderConfig, toolRelease.String(), downloadCB, ""); err != nil {
-		taskCB(&rpc.TaskProgress{Name: tr("Error downloading tool %s", toolRelease)})
-		return &cmderrors.FailedInstallError{Message: tr("Error installing tool %s", toolRelease), Cause: err}
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Error downloading tool %s", toolRelease)})
+		return &cmderrors.FailedInstallError{Message: i18n.Tr("Error installing tool %s", toolRelease), Cause: err}
 	}
 	taskCB(&rpc.TaskProgress{Completed: true})
 
 	// Install tool
-	taskCB(&rpc.TaskProgress{Name: tr("Installing tool %s", toolRelease)})
+	taskCB(&rpc.TaskProgress{Name: i18n.Tr("Installing tool %s", toolRelease)})
 	if err := toolResource.Install(pmb.DownloadDir, tmp, destDir); err != nil {
-		taskCB(&rpc.TaskProgress{Name: tr("Error installing tool %s", toolRelease)})
-		return &cmderrors.FailedInstallError{Message: tr("Error installing tool %s", toolRelease), Cause: err}
+		taskCB(&rpc.TaskProgress{Name: i18n.Tr("Error installing tool %s", toolRelease)})
+		return &cmderrors.FailedInstallError{Message: i18n.Tr("Error installing tool %s", toolRelease), Cause: err}
 	}
 	taskCB(&rpc.TaskProgress{Completed: true})
 	return nil
diff --git a/internal/arduino/cores/status.go b/internal/arduino/cores/status.go
index 85517bf7a56..42ed1177e0a 100644
--- a/internal/arduino/cores/status.go
+++ b/internal/arduino/cores/status.go
@@ -17,10 +17,10 @@ package cores
 
 import (
 	"errors"
-	"fmt"
 	"slices"
 	"strings"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	semver "go.bug.st/relaxed-semver"
 )
 
@@ -88,21 +88,21 @@ func (packages Packages) Names() []string {
 // GetPlatformReleaseToolDependencies returns the tool releases needed by the specified PlatformRelease
 func (packages Packages) GetPlatformReleaseToolDependencies(release *PlatformRelease) ([]*ToolRelease, error) {
 	if release == nil {
-		return nil, errors.New(tr("release cannot be nil"))
+		return nil, errors.New(i18n.Tr("release cannot be nil"))
 	}
 	ret := []*ToolRelease{}
 	for _, dep := range release.ToolDependencies {
 		pkg, exists := packages[dep.ToolPackager]
 		if !exists {
-			return nil, fmt.Errorf(tr("package %s not found"), dep.ToolPackager)
+			return nil, errors.New(i18n.Tr("package %s not found", dep.ToolPackager))
 		}
 		tool, exists := pkg.Tools[dep.ToolName]
 		if !exists {
-			return nil, fmt.Errorf(tr("tool %s not found"), dep.ToolName)
+			return nil, errors.New(i18n.Tr("tool %s not found", dep.ToolName))
 		}
 		toolRelease, exists := tool.Releases[dep.ToolVersion.NormalizedString()]
 		if !exists {
-			return nil, fmt.Errorf(tr("tool version %s not found"), dep.ToolVersion)
+			return nil, errors.New(i18n.Tr("tool version %s not found", dep.ToolVersion))
 		}
 		ret = append(ret, toolRelease)
 	}
@@ -112,24 +112,24 @@ func (packages Packages) GetPlatformReleaseToolDependencies(release *PlatformRel
 // GetPlatformReleaseDiscoveryDependencies returns the discovery releases needed by the specified PlatformRelease
 func (packages Packages) GetPlatformReleaseDiscoveryDependencies(release *PlatformRelease) ([]*ToolRelease, error) {
 	if release == nil {
-		return nil, fmt.Errorf(tr("release cannot be nil"))
+		return nil, errors.New(i18n.Tr("release cannot be nil"))
 	}
 
 	res := []*ToolRelease{}
 	for _, discovery := range release.DiscoveryDependencies {
 		pkg, exists := packages[discovery.Packager]
 		if !exists {
-			return nil, fmt.Errorf(tr("package %s not found"), discovery.Packager)
+			return nil, errors.New(i18n.Tr("package %s not found", discovery.Packager))
 		}
 		tool, exists := pkg.Tools[discovery.Name]
 		if !exists {
-			return nil, fmt.Errorf(tr("tool %s not found"), discovery.Name)
+			return nil, errors.New(i18n.Tr("tool %s not found", discovery.Name))
 		}
 
 		// We always want to use the latest available release for discoveries
 		latestRelease := tool.LatestRelease()
 		if latestRelease == nil {
-			return nil, fmt.Errorf(tr("can't find latest release of %s"), discovery.Name)
+			return nil, errors.New(i18n.Tr("can't find latest release of %s", discovery.Name))
 		}
 		res = append(res, latestRelease)
 	}
@@ -139,24 +139,24 @@ func (packages Packages) GetPlatformReleaseDiscoveryDependencies(release *Platfo
 // GetPlatformReleaseMonitorDependencies returns the monitor releases needed by the specified PlatformRelease
 func (packages Packages) GetPlatformReleaseMonitorDependencies(release *PlatformRelease) ([]*ToolRelease, error) {
 	if release == nil {
-		return nil, fmt.Errorf(tr("release cannot be nil"))
+		return nil, errors.New(i18n.Tr("release cannot be nil"))
 	}
 
 	res := []*ToolRelease{}
 	for _, monitor := range release.MonitorDependencies {
 		pkg, exists := packages[monitor.Packager]
 		if !exists {
-			return nil, fmt.Errorf(tr("package %s not found"), monitor.Packager)
+			return nil, errors.New(i18n.Tr("package %s not found", monitor.Packager))
 		}
 		tool, exists := pkg.Tools[monitor.Name]
 		if !exists {
-			return nil, fmt.Errorf(tr("tool %s not found"), monitor.Name)
+			return nil, errors.New(i18n.Tr("tool %s not found", monitor.Name))
 		}
 
 		// We always want to use the latest available release for monitors
 		latestRelease := tool.LatestRelease()
 		if latestRelease == nil {
-			return nil, fmt.Errorf(tr("can't find latest release of %s"), monitor.Name)
+			return nil, errors.New(i18n.Tr("can't find latest release of %s", monitor.Name))
 		}
 		res = append(res, latestRelease)
 	}
diff --git a/internal/arduino/discovery/discoverymanager/discoverymanager.go b/internal/arduino/discovery/discoverymanager/discoverymanager.go
index 74504c48062..102d0f72389 100644
--- a/internal/arduino/discovery/discoverymanager/discoverymanager.go
+++ b/internal/arduino/discovery/discoverymanager/discoverymanager.go
@@ -43,8 +43,6 @@ type DiscoveryManager struct {
 	userAgent          string
 }
 
-var tr = i18n.Tr
-
 // New creates a new DiscoveryManager
 func New(userAgent string) *DiscoveryManager {
 	return &DiscoveryManager{
@@ -132,7 +130,7 @@ func (dm *DiscoveryManager) add(d *discovery.Client) error {
 
 	id := d.GetID()
 	if _, has := dm.discoveries[id]; has {
-		return errors.New(tr("pluggable discovery already added: %s", id))
+		return errors.New(i18n.Tr("pluggable discovery already added: %s", id))
 	}
 	dm.discoveries[id] = d
 
@@ -203,11 +201,11 @@ func (dm *DiscoveryManager) startDiscovery(d *discovery.Client) (discErr error)
 	}()
 
 	if err := d.Run(); err != nil {
-		return fmt.Errorf(tr("discovery %[1]s process not started: %[2]w"), d.GetID(), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("discovery %[1]s process not started", d.GetID()), err)
 	}
 	eventCh, err := d.StartSync(5)
 	if err != nil {
-		return fmt.Errorf("%s: %s", tr("starting discovery %s", d.GetID()), err)
+		return fmt.Errorf("%s: %s", i18n.Tr("starting discovery %s", d.GetID()), err)
 	}
 
 	go func(d *discovery.Client) {
diff --git a/internal/arduino/httpclient/httpclient.go b/internal/arduino/httpclient/httpclient.go
index d8e77c7966c..8c61c5b3249 100644
--- a/internal/arduino/httpclient/httpclient.go
+++ b/internal/arduino/httpclient/httpclient.go
@@ -27,8 +27,6 @@ import (
 	"go.bug.st/downloader/v2"
 )
 
-var tr = i18n.Tr
-
 // DownloadFile downloads a file from a URL into the specified path. An optional config and options may be passed (or nil to use the defaults).
 // A DownloadProgressCB callback function must be passed to monitor download progress.
 // If a not empty queryParameter is passed, it is appended to the URL for analysis purposes.
@@ -60,7 +58,7 @@ func DownloadFile(ctx context.Context, path *paths.Path, URL string, queryParame
 
 	// The URL is not reachable for some reason
 	if d.Resp.StatusCode >= 400 && d.Resp.StatusCode <= 599 {
-		msg := tr("Server responded with: %s", d.Resp.Status)
+		msg := i18n.Tr("Server responded with: %s", d.Resp.Status)
 		return &cmderrors.FailedDownloadError{Message: msg}
 	}
 
diff --git a/internal/arduino/libraries/libraries.go b/internal/arduino/libraries/libraries.go
index 941627393f2..9ffa1e27eea 100644
--- a/internal/arduino/libraries/libraries.go
+++ b/internal/arduino/libraries/libraries.go
@@ -16,6 +16,7 @@
 package libraries
 
 import (
+	"errors"
 	"fmt"
 
 	"github.com/arduino/arduino-cli/internal/arduino/cores"
@@ -47,8 +48,6 @@ var ValidCategories = map[string]bool{
 	"Uncategorized":       true,
 }
 
-var tr = i18n.Tr
-
 // Library represents a library in the system
 type Library struct {
 	Name          string
@@ -113,7 +112,7 @@ func (library *Library) ToRPCLibrary() (*rpc.Library, error) {
 		var err error
 		headers, err = library.SourceHeaders()
 		if err != nil {
-			return nil, fmt.Errorf(tr("reading library headers: %w"), err)
+			return nil, fmt.Errorf("%s: %w", i18n.Tr("reading library headers"), err)
 		}
 	}
 
@@ -225,7 +224,7 @@ func (library *Library) SourceHeaders() ([]string, error) {
 	if library.sourceHeaders == nil {
 		cppHeaders, err := library.SourceDir.ReadDir()
 		if err != nil {
-			return nil, fmt.Errorf(tr("reading lib src dir: %s"), err)
+			return nil, errors.New(i18n.Tr("reading library source directory: %s", err))
 		}
 		headerExtensions := []string{}
 		for k := range globals.HeaderFilesValidExtensions {
diff --git a/internal/arduino/libraries/libraries_layout.go b/internal/arduino/libraries/libraries_layout.go
index 8391141322a..ced64c90654 100644
--- a/internal/arduino/libraries/libraries_layout.go
+++ b/internal/arduino/libraries/libraries_layout.go
@@ -17,8 +17,10 @@ package libraries
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -62,7 +64,7 @@ func (d *LibraryLayout) UnmarshalJSON(b []byte) error {
 		*d = RecursiveLayout
 		return nil
 	default:
-		return fmt.Errorf(tr("invalid library layout: %s"), s)
+		return errors.New(i18n.Tr("invalid library layout: %s", s))
 	}
 }
 
diff --git a/internal/arduino/libraries/libraries_location.go b/internal/arduino/libraries/libraries_location.go
index 709bca8b96f..a2a4423a54d 100644
--- a/internal/arduino/libraries/libraries_location.go
+++ b/internal/arduino/libraries/libraries_location.go
@@ -17,8 +17,10 @@ package libraries
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -85,7 +87,7 @@ func (d *LibraryLocation) UnmarshalJSON(b []byte) error {
 		*d = Unmanaged
 		return nil
 	default:
-		return fmt.Errorf(tr("invalid library location: %s"), s)
+		return errors.New(i18n.Tr("invalid library location: %s", s))
 	}
 }
 
diff --git a/internal/arduino/libraries/librariesindex/json.go b/internal/arduino/libraries/librariesindex/json.go
index 1db3db84d81..926ed39edca 100644
--- a/internal/arduino/libraries/librariesindex/json.go
+++ b/internal/arduino/libraries/librariesindex/json.go
@@ -16,7 +16,7 @@
 package librariesindex
 
 import (
-	"fmt"
+	"errors"
 
 	"github.com/arduino/arduino-cli/internal/arduino/resources"
 	"github.com/arduino/arduino-cli/internal/i18n"
@@ -57,19 +57,17 @@ type indexDependency struct {
 	Version string `json:"version,omitempty"`
 }
 
-var tr = i18n.Tr
-
 // LoadIndex reads a library_index.json and create the corresponding Index
 func LoadIndex(indexFile *paths.Path) (*Index, error) {
 	buff, err := indexFile.ReadFile()
 	if err != nil {
-		return nil, fmt.Errorf(tr("reading library_index.json: %s"), err)
+		return nil, errors.New(i18n.Tr("reading library_index.json: %s", err))
 	}
 
 	var i indexJSON
 	err = easyjson.Unmarshal(buff, &i)
 	if err != nil {
-		return nil, fmt.Errorf(tr("parsing library_index.json: %s"), err)
+		return nil, errors.New(i18n.Tr("parsing library_index.json: %s", err))
 	}
 
 	return i.extractIndex()
diff --git a/internal/arduino/libraries/librariesmanager/install.go b/internal/arduino/libraries/librariesmanager/install.go
index 4517756e3e7..99c7914fc09 100644
--- a/internal/arduino/libraries/librariesmanager/install.go
+++ b/internal/arduino/libraries/librariesmanager/install.go
@@ -17,6 +17,7 @@ package librariesmanager
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net/url"
 	"os"
@@ -26,6 +27,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
 	"github.com/arduino/arduino-cli/internal/arduino/libraries"
 	"github.com/arduino/arduino-cli/internal/arduino/utils"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	paths "github.com/arduino/go-paths-helper"
 	"github.com/codeclysm/extract/v3"
 	"github.com/go-git/go-git/v5"
@@ -74,7 +76,7 @@ func (lmi *Installer) InstallPrerequisiteCheck(name string, version *semver.Vers
 		return nil, &cmderrors.MultipleLibraryInstallDetected{
 			LibName: name,
 			LibsDir: libsDir,
-			Message: tr("Automatic library install can't be performed in this case, please manually remove all duplicates and retry."),
+			Message: i18n.Tr("Automatic library install can't be performed in this case, please manually remove all duplicates and retry."),
 		}
 	}
 
@@ -89,7 +91,7 @@ func (lmi *Installer) InstallPrerequisiteCheck(name string, version *semver.Vers
 	libPath := installDir.Join(utils.SanitizeName(name))
 	if libPath.IsDir() {
 		if replaced == nil || !replaced.InstallDir.EquivalentTo(libPath) {
-			return nil, fmt.Errorf(tr("destination dir %s already exists, cannot install"), libPath)
+			return nil, errors.New(i18n.Tr("destination dir %s already exists, cannot install", libPath))
 		}
 	}
 
@@ -121,22 +123,22 @@ func (lmi *Installer) importLibraryFromDirectory(libPath *paths.Path, overwrite
 
 	if installPlan.UpToDate {
 		if !overwrite {
-			return fmt.Errorf(tr("library %s already installed"), installPlan.Name)
+			return errors.New(i18n.Tr("library %s already installed", installPlan.Name))
 		}
 	}
 	if installPlan.ReplacedLib != nil {
 		if !overwrite {
-			return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", installPlan.Name, installPlan.ReplacedLib))
+			return errors.New(i18n.Tr("Library %[1]s is already installed, but with a different version: %[2]s", installPlan.Name, installPlan.ReplacedLib))
 		}
 		if err := lmi.Uninstall(installPlan.ReplacedLib); err != nil {
 			return err
 		}
 	}
 	if installPlan.TargetPath.Exist() {
-		return fmt.Errorf("%s: %s", tr("destination directory already exists"), installPlan.TargetPath)
+		return fmt.Errorf("%s: %s", i18n.Tr("destination directory already exists"), installPlan.TargetPath)
 	}
 	if err := libPath.CopyDirTo(installPlan.TargetPath); err != nil {
-		return fmt.Errorf("%s: %w", tr("copying library to destination directory:"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("copying library to destination directory:"), err)
 	}
 	return nil
 }
@@ -144,10 +146,10 @@ func (lmi *Installer) importLibraryFromDirectory(libPath *paths.Path, overwrite
 // Uninstall removes a Library
 func (lmi *Installer) Uninstall(lib *libraries.Library) error {
 	if lib == nil || lib.InstallDir == nil {
-		return fmt.Errorf(tr("install directory not set"))
+		return errors.New(i18n.Tr("install directory not set"))
 	}
 	if err := lib.InstallDir.RemoveAll(); err != nil {
-		return fmt.Errorf(tr("removing library directory: %s"), err)
+		return errors.New(i18n.Tr("removing library directory: %s", err))
 	}
 
 	alternatives := lmi.libraries[lib.Name]
@@ -174,7 +176,7 @@ func (lmi *Installer) InstallZipLib(ctx context.Context, archivePath *paths.Path
 	// Extract to a temporary directory so we can check if the zip is structured correctly.
 	// We also use the top level folder from the archive to infer the library name.
 	if err := extract.Archive(ctx, file, tmpDir.String(), nil); err != nil {
-		return fmt.Errorf(tr("extracting archive: %w"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("extracting archive"), err)
 	}
 
 	libRootFiles, err := tmpDir.ReadDir()
@@ -183,16 +185,16 @@ func (lmi *Installer) InstallZipLib(ctx context.Context, archivePath *paths.Path
 	}
 	libRootFiles.FilterOutPrefix("__MACOSX") // Ignores metadata from Mac OS X
 	if len(libRootFiles) > 1 {
-		return fmt.Errorf(tr("archive is not valid: multiple files found in zip file top level"))
+		return errors.New(i18n.Tr("archive is not valid: multiple files found in zip file top level"))
 	}
 	if len(libRootFiles) == 0 {
-		return fmt.Errorf(tr("archive is not valid: no files found in zip file top level"))
+		return errors.New(i18n.Tr("archive is not valid: no files found in zip file top level"))
 	}
 	tmpInstallPath := libRootFiles[0]
 
 	// Install extracted library in the destination directory
 	if err := lmi.importLibraryFromDirectory(tmpInstallPath, overwrite); err != nil {
-		return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err)
+		return errors.New(i18n.Tr("moving extracted archive to destination dir: %s", err))
 	}
 
 	return nil
@@ -241,7 +243,7 @@ func (lmi *Installer) InstallGitLib(gitURL string, overwrite bool) error {
 
 	// Install extracted library in the destination directory
 	if err := lmi.importLibraryFromDirectory(tmpInstallPath, overwrite); err != nil {
-		return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err)
+		return errors.New(i18n.Tr("moving extracted archive to destination dir: %s", err))
 	}
 
 	return nil
@@ -263,7 +265,7 @@ func parseGitURL(gitURL string) (string, plumbing.Revision, error) {
 		res = strings.TrimSuffix(parsed.Path[i+1:], ".git")
 		rev = plumbing.Revision(parsed.Fragment)
 	} else {
-		return "", "", fmt.Errorf(tr("invalid git url"))
+		return "", "", errors.New(i18n.Tr("invalid git url"))
 	}
 	return res, rev, nil
 }
@@ -273,7 +275,7 @@ func parseGitURL(gitURL string) (string, plumbing.Revision, error) {
 // Returns nil if dir contains a valid library, error on all other cases.
 func validateLibrary(dir *paths.Path) error {
 	if dir.NotExist() {
-		return fmt.Errorf(tr("directory doesn't exist: %s", dir))
+		return errors.New(i18n.Tr("directory doesn't exist: %s", dir))
 	}
 
 	searchHeaderFile := func(d *paths.Path) (bool, error) {
@@ -283,7 +285,7 @@ func validateLibrary(dir *paths.Path) error {
 		}
 		dirContent, err := d.ReadDir()
 		if err != nil {
-			return false, fmt.Errorf(tr("reading directory %s content: %w", dir, err))
+			return false, fmt.Errorf("%s: %w", i18n.Tr("reading directory %s content", dir), err)
 		}
 		dirContent.FilterOutDirs()
 		headerExtensions := []string{}
@@ -310,5 +312,5 @@ func validateLibrary(dir *paths.Path) error {
 		return nil
 	}
 
-	return fmt.Errorf(tr("library not valid"))
+	return errors.New(i18n.Tr("library not valid"))
 }
diff --git a/internal/arduino/libraries/librariesmanager/librariesmanager.go b/internal/arduino/libraries/librariesmanager/librariesmanager.go
index 123513b2d31..f5883d6673b 100644
--- a/internal/arduino/libraries/librariesmanager/librariesmanager.go
+++ b/internal/arduino/libraries/librariesmanager/librariesmanager.go
@@ -68,8 +68,6 @@ type LibrariesDir struct {
 	scanned         bool
 }
 
-var tr = i18n.Tr
-
 // Names returns an array with all the names of the installed libraries.
 func (lm *Explorer) Names() []string {
 	res := make([]string, len(lm.libraries))
@@ -188,9 +186,9 @@ func (lm *LibrariesManager) getLibrariesDir(installLocation libraries.LibraryLoc
 	}
 	switch installLocation {
 	case libraries.User:
-		return nil, errors.New(tr("user directory not set"))
+		return nil, errors.New(i18n.Tr("user directory not set"))
 	case libraries.IDEBuiltIn:
-		return nil, errors.New(tr("built-in libraries directory not set"))
+		return nil, errors.New(i18n.Tr("built-in libraries directory not set"))
 	default:
 		return nil, fmt.Errorf("libraries directory not set: %s", installLocation.String())
 	}
@@ -212,7 +210,7 @@ func (lm *LibrariesManager) loadLibrariesFromDir(librariesDir *LibrariesDir) []*
 			return statuses
 		}
 		if err != nil {
-			s := status.Newf(codes.FailedPrecondition, tr("reading dir %[1]s: %[2]s"), librariesDir.Path, err)
+			s := status.Newf(codes.FailedPrecondition, i18n.Tr("reading dir %[1]s: %[2]s", librariesDir.Path, err))
 			return append(statuses, s)
 		}
 		d.FilterDirs()
@@ -223,7 +221,7 @@ func (lm *LibrariesManager) loadLibrariesFromDir(librariesDir *LibrariesDir) []*
 	for _, libDir := range libDirs {
 		library, err := libraries.Load(libDir, librariesDir.Location)
 		if err != nil {
-			s := status.Newf(codes.Internal, tr("loading library from %[1]s: %[2]s"), libDir, err)
+			s := status.Newf(codes.Internal, i18n.Tr("loading library from %[1]s: %[2]s", libDir, err))
 			statuses = append(statuses, s)
 			continue
 		}
diff --git a/internal/arduino/libraries/librariesresolver/cpp.go b/internal/arduino/libraries/librariesresolver/cpp.go
index 7f11f8a66c8..e842b764ace 100644
--- a/internal/arduino/libraries/librariesresolver/cpp.go
+++ b/internal/arduino/libraries/librariesresolver/cpp.go
@@ -16,6 +16,7 @@
 package librariesresolver
 
 import (
+	"errors"
 	"fmt"
 	"path/filepath"
 	"strings"
@@ -33,8 +34,6 @@ type Cpp struct {
 	headers map[string]libraries.List
 }
 
-var tr = i18n.Tr
-
 // NewCppResolver creates a new Cpp resolver
 func NewCppResolver(allLibs []*libraries.Library, targetPlatform, actualPlatform *cores.PlatformRelease) *Cpp {
 	resolver := &Cpp{
@@ -88,7 +87,7 @@ func (resolver *Cpp) ScanPlatformLibraries(allLibs []*libraries.Library, platfor
 func (resolver *Cpp) ScanLibrary(lib *libraries.Library) error {
 	cppHeaders, err := lib.SourceHeaders()
 	if err != nil {
-		return fmt.Errorf(tr("reading lib headers: %s"), err)
+		return errors.New(i18n.Tr("reading lib headers: %s", err))
 	}
 	for _, cppHeader := range cppHeaders {
 		l := resolver.headers[cppHeader]
diff --git a/internal/arduino/libraries/loader.go b/internal/arduino/libraries/loader.go
index 61f71f4928f..f3d3c896383 100644
--- a/internal/arduino/libraries/loader.go
+++ b/internal/arduino/libraries/loader.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	properties "github.com/arduino/go-properties-orderedmap"
 	semver "go.bug.st/relaxed-semver"
@@ -51,7 +52,7 @@ func addUtilityDirectory(library *Library) {
 func makeNewLibrary(libraryDir *paths.Path, location LibraryLocation) (*Library, error) {
 	libProperties, err := properties.Load(libraryDir.Join("library.properties").String())
 	if err != nil {
-		return nil, fmt.Errorf(tr("loading library.properties: %s"), err)
+		return nil, errors.New(i18n.Tr("loading library.properties: %s", err))
 	}
 
 	if libProperties.Get("maintainer") == "" && libProperties.Get("email") != "" {
@@ -113,7 +114,7 @@ func makeNewLibrary(libraryDir *paths.Path, location LibraryLocation) (*Library,
 	}
 
 	if err := addExamples(library); err != nil {
-		return nil, fmt.Errorf("%s: %w", tr("scanning sketch examples"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("scanning sketch examples"), err)
 	}
 	library.DirName = libraryDir.Base()
 	library.Name = strings.TrimSpace(libProperties.Get("name"))
@@ -136,7 +137,7 @@ func makeLegacyLibrary(path *paths.Path, location LibraryLocation) (*Library, er
 	if foundHeader, err := containsHeaderFile(path); err != nil {
 		return nil, err
 	} else if !foundHeader {
-		return nil, errors.New(tr("invalid library: no header files found"))
+		return nil, errors.New(i18n.Tr("invalid library: no header files found"))
 	}
 	library := &Library{
 		InstallDir:    path.Canonical(),
@@ -151,7 +152,7 @@ func makeLegacyLibrary(path *paths.Path, location LibraryLocation) (*Library, er
 		InDevelopment: path.Join(".development").Exist(),
 	}
 	if err := addExamples(library); err != nil {
-		return nil, fmt.Errorf("%s: %w", tr("scanning sketch examples"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("scanning sketch examples"), err)
 	}
 	addUtilityDirectory(library)
 	return library, nil
@@ -195,7 +196,7 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error
 func containsHeaderFile(d *paths.Path) (bool, error) {
 	dirContent, err := d.ReadDir()
 	if err != nil {
-		return false, fmt.Errorf(tr("reading directory %[1]s content: %[2]w", d, err))
+		return false, fmt.Errorf("%s: %w", i18n.Tr("reading directory %[1]s content", d), err)
 	}
 	dirContent.FilterOutDirs()
 	headerExtensions := []string{}
diff --git a/internal/arduino/monitor/monitor.go b/internal/arduino/monitor/monitor.go
index cf993e5029d..b4603f0b6c2 100644
--- a/internal/arduino/monitor/monitor.go
+++ b/internal/arduino/monitor/monitor.go
@@ -20,6 +20,7 @@ package monitor
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -83,8 +84,6 @@ func (msg monitorMessage) String() string {
 	return s
 }
 
-var tr = i18n.Tr
-
 // New create and connect to the given pluggable monitor
 func New(id string, args ...string) *PluggableMonitor {
 	return &PluggableMonitor{
@@ -137,20 +136,20 @@ func (mon *PluggableMonitor) waitMessage(timeout time.Duration, expectedEvt stri
 		}
 		msg = m
 	case <-time.After(timeout):
-		return nil, fmt.Errorf(tr("timeout waiting for message"))
+		return nil, errors.New(i18n.Tr("timeout waiting for message"))
 	}
 	if expectedEvt == "" {
 		// No message processing required for this call
 		return msg, nil
 	}
 	if msg.EventType != expectedEvt {
-		return msg, fmt.Errorf(tr("communication out of sync, expected '%[1]s', received '%[2]s'"), expectedEvt, msg.EventType)
+		return msg, errors.New(i18n.Tr("communication out of sync, expected '%[1]s', received '%[2]s'", expectedEvt, msg.EventType))
 	}
 	if msg.Error {
-		return msg, fmt.Errorf(tr("command '%[1]s' failed: %[2]s"), expectedEvt, msg.Message)
+		return msg, errors.New(i18n.Tr("command '%[1]s' failed: %[2]s", expectedEvt, msg.Message))
 	}
 	if strings.ToUpper(msg.Message) != "OK" {
-		return msg, fmt.Errorf(tr("communication out of sync, expected '%[1]s', received '%[2]s'"), "OK", msg.Message)
+		return msg, errors.New(i18n.Tr("communication out of sync, expected '%[1]s', received '%[2]s'", "OK", msg.Message))
 	}
 	return msg, nil
 }
@@ -233,7 +232,7 @@ func (mon *PluggableMonitor) Run() (err error) {
 	if msg, err := mon.waitMessage(time.Second*10, "hello"); err != nil {
 		return err
 	} else if msg.ProtocolVersion > 1 {
-		return fmt.Errorf(tr("protocol version not supported: requested %[1]d, got %[2]d"), 1, msg.ProtocolVersion)
+		return errors.New(i18n.Tr("protocol version not supported: requested %[1]d, got %[2]d", 1, msg.ProtocolVersion))
 	}
 	return nil
 }
diff --git a/internal/arduino/resources/checksums.go b/internal/arduino/resources/checksums.go
index 25ec3a6996b..ecd50b5bcc9 100644
--- a/internal/arduino/resources/checksums.go
+++ b/internal/arduino/resources/checksums.go
@@ -21,6 +21,7 @@ import (
 	"crypto/sha256"
 	"encoding/hex"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"hash"
 	"io"
@@ -32,20 +33,18 @@ import (
 	paths "github.com/arduino/go-paths-helper"
 )
 
-var tr = i18n.Tr
-
 // TestLocalArchiveChecksum test if the checksum of the local archive match the checksum of the DownloadResource
 func (r *DownloadResource) TestLocalArchiveChecksum(downloadDir *paths.Path) (bool, error) {
 	if r.Checksum == "" {
-		return false, fmt.Errorf(tr("missing checksum for: %s"), r.ArchiveFileName)
+		return false, errors.New(i18n.Tr("missing checksum for: %s", r.ArchiveFileName))
 	}
 	split := strings.SplitN(r.Checksum, ":", 2)
 	if len(split) != 2 {
-		return false, fmt.Errorf(tr("invalid checksum format: %s"), r.Checksum)
+		return false, errors.New(i18n.Tr("invalid checksum format: %s", r.Checksum))
 	}
 	digest, err := hex.DecodeString(split[1])
 	if err != nil {
-		return false, fmt.Errorf(tr("invalid hash '%[1]s': %[2]s"), split[1], err)
+		return false, errors.New(i18n.Tr("invalid hash '%[1]s': %[2]s", split[1], err))
 	}
 
 	// names based on: https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest
@@ -58,25 +57,25 @@ func (r *DownloadResource) TestLocalArchiveChecksum(downloadDir *paths.Path) (bo
 	case "MD5":
 		algo = crypto.MD5.New()
 	default:
-		return false, fmt.Errorf(tr("unsupported hash algorithm: %s"), split[0])
+		return false, errors.New(i18n.Tr("unsupported hash algorithm: %s", split[0]))
 	}
 
 	filePath, err := r.ArchivePath(downloadDir)
 	if err != nil {
-		return false, fmt.Errorf(tr("getting archive path: %s"), err)
+		return false, errors.New(i18n.Tr("getting archive path: %s", err))
 	}
 
 	file, err := os.Open(filePath.String())
 	if err != nil {
-		return false, fmt.Errorf(tr("opening archive file: %s"), err)
+		return false, errors.New(i18n.Tr("opening archive file: %s", err))
 	}
 	defer file.Close()
 	if _, err := io.Copy(algo, file); err != nil {
-		return false, fmt.Errorf(tr("computing hash: %s"), err)
+		return false, errors.New(i18n.Tr("computing hash: %s", err))
 	}
 
 	if !bytes.Equal(algo.Sum(nil), digest) {
-		return false, fmt.Errorf(tr("archive hash differs from hash in index"))
+		return false, errors.New(i18n.Tr("archive hash differs from hash in index"))
 	}
 
 	return true, nil
@@ -86,14 +85,14 @@ func (r *DownloadResource) TestLocalArchiveChecksum(downloadDir *paths.Path) (bo
 func (r *DownloadResource) TestLocalArchiveSize(downloadDir *paths.Path) (bool, error) {
 	filePath, err := r.ArchivePath(downloadDir)
 	if err != nil {
-		return false, fmt.Errorf(tr("getting archive path: %s"), err)
+		return false, errors.New(i18n.Tr("getting archive path: %s", err))
 	}
 	info, err := filePath.Stat()
 	if err != nil {
-		return false, fmt.Errorf(tr("getting archive info: %s"), err)
+		return false, errors.New(i18n.Tr("getting archive info: %s", err))
 	}
 	if info.Size() != r.Size {
-		return false, fmt.Errorf("%s: %d != %d", tr("fetched archive size differs from size specified in index"), info.Size(), r.Size)
+		return false, fmt.Errorf("%s: %d != %d", i18n.Tr("fetched archive size differs from size specified in index"), info.Size(), r.Size)
 	}
 
 	return true, nil
@@ -102,20 +101,20 @@ func (r *DownloadResource) TestLocalArchiveSize(downloadDir *paths.Path) (bool,
 // TestLocalArchiveIntegrity checks for integrity of the local archive.
 func (r *DownloadResource) TestLocalArchiveIntegrity(downloadDir *paths.Path) (bool, error) {
 	if cached, err := r.IsCached(downloadDir); err != nil {
-		return false, fmt.Errorf(tr("testing if archive is cached: %s"), err)
+		return false, errors.New(i18n.Tr("testing if archive is cached: %s", err))
 	} else if !cached {
 		return false, nil
 	}
 
 	if ok, err := r.TestLocalArchiveSize(downloadDir); err != nil {
-		return false, fmt.Errorf(tr("testing archive size: %s"), err)
+		return false, errors.New(i18n.Tr("testing archive size: %s", err))
 	} else if !ok {
 		return false, nil
 	}
 
 	ok, err := r.TestLocalArchiveChecksum(downloadDir)
 	if err != nil {
-		return false, fmt.Errorf(tr("testing archive checksum: %s"), err)
+		return false, errors.New(i18n.Tr("testing archive checksum: %s", err))
 	}
 	return ok, nil
 }
@@ -141,7 +140,7 @@ func computeDirChecksum(root string) (string, error) {
 		}
 		defer f.Close()
 		if _, err := io.Copy(hash, f); err != nil {
-			return fmt.Errorf(tr("failed to compute hash of file \"%s\""), info.Name())
+			return errors.New(i18n.Tr("failed to compute hash of file \"%s\"", info.Name()))
 		}
 		return nil
 	})
@@ -164,7 +163,7 @@ func CheckDirChecksum(root string) (bool, error) {
 		return false, err
 	}
 	if file.Checksum != checksum {
-		return false, fmt.Errorf(tr("Checksum differs from checksum in package.json"))
+		return false, errors.New(i18n.Tr("Checksum differs from checksum in package.json"))
 	}
 
 	return true, nil
diff --git a/internal/arduino/resources/download.go b/internal/arduino/resources/download.go
index 1699be86ecc..37c622b2aab 100644
--- a/internal/arduino/resources/download.go
+++ b/internal/arduino/resources/download.go
@@ -17,10 +17,11 @@ package resources
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"os"
 
 	"github.com/arduino/arduino-cli/internal/arduino/httpclient"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
 	"go.bug.st/downloader/v2"
@@ -32,7 +33,7 @@ import (
 func (r *DownloadResource) Download(ctx context.Context, downloadDir *paths.Path, config downloader.Config, label string, downloadCB rpc.DownloadProgressCB, queryParameter string) error {
 	path, err := r.ArchivePath(downloadDir)
 	if err != nil {
-		return fmt.Errorf(tr("getting archive path: %s"), err)
+		return errors.New(i18n.Tr("getting archive path: %s", err))
 	}
 
 	if _, err := path.Stat(); os.IsNotExist(err) {
@@ -42,16 +43,16 @@ func (r *DownloadResource) Download(ctx context.Context, downloadDir *paths.Path
 		ok, err := r.TestLocalArchiveIntegrity(downloadDir)
 		if err != nil || !ok {
 			if err := path.Remove(); err != nil {
-				return fmt.Errorf(tr("removing corrupted archive file: %s"), err)
+				return errors.New(i18n.Tr("removing corrupted archive file: %s", err))
 			}
 		} else {
 			// File is cached, nothing to do here
 			downloadCB.Start(r.URL, label)
-			downloadCB.End(true, tr("%s already downloaded", label))
+			downloadCB.End(true, i18n.Tr("%s already downloaded", label))
 			return nil
 		}
 	} else {
-		return fmt.Errorf(tr("getting archive file info: %s"), err)
+		return errors.New(i18n.Tr("getting archive file info: %s", err))
 	}
 	return httpclient.DownloadFile(ctx, path, r.URL, queryParameter, label, downloadCB, config)
 }
diff --git a/internal/arduino/resources/helpers.go b/internal/arduino/resources/helpers.go
index 39349dd28a9..c9f87e7d02e 100644
--- a/internal/arduino/resources/helpers.go
+++ b/internal/arduino/resources/helpers.go
@@ -16,8 +16,9 @@
 package resources
 
 import (
-	"fmt"
+	"errors"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 )
 
@@ -35,7 +36,7 @@ func (r *DownloadResource) ArchivePath(downloadDir *paths.Path) (*paths.Path, er
 func (r *DownloadResource) IsCached(downloadDir *paths.Path) (bool, error) {
 	archivePath, err := r.ArchivePath(downloadDir)
 	if err != nil {
-		return false, fmt.Errorf(tr("getting archive path: %s"), err)
+		return false, errors.New(i18n.Tr("getting archive path: %s", err))
 	}
 	return archivePath.Exist(), nil
 }
diff --git a/internal/arduino/resources/index.go b/internal/arduino/resources/index.go
index 57445e5643b..52c2dec2884 100644
--- a/internal/arduino/resources/index.go
+++ b/internal/arduino/resources/index.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/arduino/httpclient"
 	"github.com/arduino/arduino-cli/internal/arduino/security"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/codeclysm/extract/v3"
@@ -61,7 +62,7 @@ func (res *IndexResource) IndexFileName() (string, error) {
 func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, downloadCB rpc.DownloadProgressCB, config downloader.Config) error {
 	// Create destination directory
 	if err := destDir.MkdirAll(); err != nil {
-		return &cmderrors.PermissionDeniedError{Message: tr("Can't create data directory %s", destDir), Cause: err}
+		return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Can't create data directory %s", destDir), Cause: err}
 	}
 
 	// Create a temp dir to stage all downloads
@@ -78,8 +79,8 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
 		return err
 	}
 	tmpIndexPath := tmp.Join(downloadFileName)
-	if err := httpclient.DownloadFile(ctx, tmpIndexPath, res.URL.String(), "", tr("Downloading index: %s", downloadFileName), downloadCB, config, downloader.NoResume); err != nil {
-		return &cmderrors.FailedDownloadError{Message: tr("Error downloading index '%s'", res.URL), Cause: err}
+	if err := httpclient.DownloadFile(ctx, tmpIndexPath, res.URL.String(), "", i18n.Tr("Downloading index: %s", downloadFileName), downloadCB, config, downloader.NoResume); err != nil {
+		return &cmderrors.FailedDownloadError{Message: i18n.Tr("Error downloading index '%s'", res.URL), Cause: err}
 	}
 
 	var signaturePath, tmpSignaturePath *paths.Path
@@ -95,19 +96,19 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
 		// Extract archive in a tmp/archive subdirectory
 		f, err := tmpIndexPath.Open()
 		if err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error opening %s", tmpIndexPath), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error opening %s", tmpIndexPath), Cause: err}
 		}
 		defer f.Close()
 		tmpArchivePath := tmp.Join("archive")
 		_ = tmpArchivePath.MkdirAll()
 		if err := extract.Bz2(ctx, f, tmpArchivePath.String(), nil); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error extracting %s", tmpIndexPath), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error extracting %s", tmpIndexPath), Cause: err}
 		}
 
 		// Look for index.json
 		tmpIndexPath = tmpArchivePath.Join(indexFileName)
 		if !tmpIndexPath.Exist() {
-			return &cmderrors.NotFoundError{Message: tr("Invalid archive: file %{1}s not found in archive %{2}s", indexFileName, tmpArchivePath.Base())}
+			return &cmderrors.NotFoundError{Message: i18n.Tr("Invalid archive: file %[1]s not found in archive %[2]s", indexFileName, tmpArchivePath.Base())}
 		}
 
 		// Look for signature
@@ -120,7 +121,7 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
 	} else if strings.HasSuffix(downloadFileName, ".gz") {
 		tmpUnzippedIndexPath := tmp.Join(indexFileName)
 		if err := paths.GUnzip(tmpIndexPath, tmpUnzippedIndexPath); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error extracting %s", indexFileName), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error extracting %s", indexFileName), Cause: err}
 		}
 		tmpIndexPath = tmpUnzippedIndexPath
 	}
@@ -133,8 +134,8 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
 		// Download signature
 		signaturePath = destDir.Join(signatureFileName)
 		tmpSignaturePath = tmp.Join(signatureFileName)
-		if err := httpclient.DownloadFile(ctx, tmpSignaturePath, res.SignatureURL.String(), "", tr("Downloading index signature: %s", signatureFileName), downloadCB, config, downloader.NoResume); err != nil {
-			return &cmderrors.FailedDownloadError{Message: tr("Error downloading index signature '%s'", res.SignatureURL), Cause: err}
+		if err := httpclient.DownloadFile(ctx, tmpSignaturePath, res.SignatureURL.String(), "", i18n.Tr("Downloading index signature: %s", signatureFileName), downloadCB, config, downloader.NoResume); err != nil {
+			return &cmderrors.FailedDownloadError{Message: i18n.Tr("Error downloading index signature '%s'", res.SignatureURL), Cause: err}
 		}
 
 		hasSignature = true
@@ -143,13 +144,13 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
 	if hasSignature {
 		// Check signature...
 		if valid, _, err := security.VerifyArduinoDetachedSignature(tmpIndexPath, tmpSignaturePath); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error verifying signature"), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error verifying signature"), Cause: err}
 		} else if !valid {
 			return &cmderrors.SignatureVerificationFailedError{File: res.URL.String()}
 		}
 	} else {
 		if res.EnforceSignatureVerification {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error verifying signature"), Cause: errors.New(tr("missing signature"))}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error verifying signature"), Cause: errors.New(i18n.Tr("missing signature"))}
 		}
 	}
 
@@ -161,23 +162,23 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
 	oldIndex := tmp.Join("old_index")
 	if indexPath.Exist() {
 		if err := indexPath.CopyTo(oldIndex); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error saving downloaded index"), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error saving downloaded index"), Cause: err}
 		}
 		defer oldIndex.CopyTo(indexPath) // will silently fail in case of success
 	}
 	oldSignature := tmp.Join("old_signature")
 	if oldSignature.Exist() {
 		if err := signaturePath.CopyTo(oldSignature); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error saving downloaded index signature"), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error saving downloaded index signature"), Cause: err}
 		}
 		defer oldSignature.CopyTo(signaturePath) // will silently fail in case of success
 	}
 	if err := tmpIndexPath.CopyTo(indexPath); err != nil {
-		return &cmderrors.PermissionDeniedError{Message: tr("Error saving downloaded index"), Cause: err}
+		return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error saving downloaded index"), Cause: err}
 	}
 	if hasSignature {
 		if err := tmpSignaturePath.CopyTo(signaturePath); err != nil {
-			return &cmderrors.PermissionDeniedError{Message: tr("Error saving downloaded index signature"), Cause: err}
+			return &cmderrors.PermissionDeniedError{Message: i18n.Tr("Error saving downloaded index signature"), Cause: err}
 		}
 	}
 	_ = oldIndex.Remove()
diff --git a/internal/arduino/resources/install.go b/internal/arduino/resources/install.go
index 4c98b4be37d..76ce5de2232 100644
--- a/internal/arduino/resources/install.go
+++ b/internal/arduino/resources/install.go
@@ -17,9 +17,10 @@ package resources
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"os"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	paths "github.com/arduino/go-paths-helper"
 	"github.com/codeclysm/extract/v3"
 	"go.bug.st/cleanup"
@@ -34,29 +35,29 @@ import (
 func (release *DownloadResource) Install(downloadDir, tempPath, destDir *paths.Path) error {
 	// Check the integrity of the package
 	if ok, err := release.TestLocalArchiveIntegrity(downloadDir); err != nil {
-		return fmt.Errorf(tr("testing local archive integrity: %s", err))
+		return errors.New(i18n.Tr("testing local archive integrity: %s", err))
 	} else if !ok {
-		return fmt.Errorf(tr("checking local archive integrity"))
+		return errors.New(i18n.Tr("checking local archive integrity"))
 	}
 
 	// Create a temporary dir to extract package
 	if err := tempPath.MkdirAll(); err != nil {
-		return fmt.Errorf(tr("creating temp dir for extraction: %s", err))
+		return errors.New(i18n.Tr("creating temp dir for extraction: %s", err))
 	}
 	tempDir, err := tempPath.MkTempDir("package-")
 	if err != nil {
-		return fmt.Errorf(tr("creating temp dir for extraction: %s", err))
+		return errors.New(i18n.Tr("creating temp dir for extraction: %s", err))
 	}
 	defer tempDir.RemoveAll()
 
 	// Obtain the archive path and open it
 	archivePath, err := release.ArchivePath(downloadDir)
 	if err != nil {
-		return fmt.Errorf(tr("getting archive path: %s", err))
+		return errors.New(i18n.Tr("getting archive path: %s", err))
 	}
 	file, err := os.Open(archivePath.String())
 	if err != nil {
-		return fmt.Errorf(tr("opening archive file: %s", err))
+		return errors.New(i18n.Tr("opening archive file: %s", err))
 	}
 	defer file.Close()
 
@@ -64,13 +65,13 @@ func (release *DownloadResource) Install(downloadDir, tempPath, destDir *paths.P
 	ctx, cancel := cleanup.InterruptableContext(context.Background())
 	defer cancel()
 	if err := extract.Archive(ctx, file, tempDir.String(), nil); err != nil {
-		return fmt.Errorf(tr("extracting archive: %s", err))
+		return errors.New(i18n.Tr("extracting archive: %s", err))
 	}
 
 	// Check package content and find package root dir
 	root, err := findPackageRoot(tempDir)
 	if err != nil {
-		return fmt.Errorf(tr("searching package root dir: %s", err))
+		return errors.New(i18n.Tr("searching package root dir: %s", err))
 	}
 
 	// Ensure container dir exists
@@ -93,7 +94,7 @@ func (release *DownloadResource) Install(downloadDir, tempPath, destDir *paths.P
 	if err := root.Rename(destDir); err != nil {
 		// Copy the extracted root directory to the destination directory, if move failed
 		if err := root.CopyDirTo(destDir); err != nil {
-			return fmt.Errorf(tr("moving extracted archive to destination dir: %s", err))
+			return errors.New(i18n.Tr("moving extracted archive to destination dir: %s", err))
 		}
 	}
 
@@ -112,17 +113,17 @@ func IsDirEmpty(path *paths.Path) (bool, error) {
 func findPackageRoot(parent *paths.Path) (*paths.Path, error) {
 	files, err := parent.ReadDir()
 	if err != nil {
-		return nil, fmt.Errorf(tr("reading package root dir: %s", err))
+		return nil, errors.New(i18n.Tr("reading package root dir: %s", err))
 	}
 
 	files.FilterDirs()
 	files.FilterOutPrefix("__MACOSX")
 
 	if len(files) == 0 {
-		return nil, fmt.Errorf(tr("files in archive must be placed in a subdirectory"))
+		return nil, errors.New(i18n.Tr("files in archive must be placed in a subdirectory"))
 	}
 	if len(files) > 1 {
-		return nil, fmt.Errorf(tr("no unique root dir in archive, found '%[1]s' and '%[2]s'", files[0], files[1]))
+		return nil, errors.New(i18n.Tr("no unique root dir in archive, found '%[1]s' and '%[2]s'", files[0], files[1]))
 	}
 
 	return files[0], nil
diff --git a/internal/arduino/security/signatures.go b/internal/arduino/security/signatures.go
index f6e6315c8f8..fb6ed9b0697 100644
--- a/internal/arduino/security/signatures.go
+++ b/internal/arduino/security/signatures.go
@@ -17,7 +17,7 @@ package security
 
 import (
 	"embed"
-	"fmt"
+	"errors"
 	"io"
 	"os"
 
@@ -26,8 +26,6 @@ import (
 	"github.com/arduino/go-paths-helper"
 )
 
-var tr = i18n.Tr
-
 //go:embed keys/*
 var keys embed.FS
 
@@ -71,16 +69,16 @@ func VerifyDetachedSignature(targetPath *paths.Path, signaturePath *paths.Path,
 func VerifySignature(targetPath *paths.Path, signaturePath *paths.Path, arduinoKeyringFile io.Reader) (bool, *openpgp.Entity, error) {
 	keyRing, err := openpgp.ReadKeyRing(arduinoKeyringFile)
 	if err != nil {
-		return false, nil, fmt.Errorf(tr("retrieving Arduino public keys: %s"), err)
+		return false, nil, errors.New(i18n.Tr("retrieving Arduino public keys: %s", err))
 	}
 	target, err := targetPath.Open()
 	if err != nil {
-		return false, nil, fmt.Errorf(tr("opening target file: %s"), err)
+		return false, nil, errors.New(i18n.Tr("opening target file: %s", err))
 	}
 	defer target.Close()
 	signature, err := signaturePath.Open()
 	if err != nil {
-		return false, nil, fmt.Errorf(tr("opening signature file: %s"), err)
+		return false, nil, errors.New(i18n.Tr("opening signature file: %s", err))
 	}
 	defer signature.Close()
 	signer, err := openpgp.CheckDetachedSignature(keyRing, target, signature, nil)
diff --git a/internal/arduino/sketch/profiles.go b/internal/arduino/sketch/profiles.go
index a30d0f95438..b01bec167f2 100644
--- a/internal/arduino/sketch/profiles.go
+++ b/internal/arduino/sketch/profiles.go
@@ -18,12 +18,14 @@ package sketch
 import (
 	"crypto/sha256"
 	"encoding/hex"
+	"errors"
 	"fmt"
 	"net/url"
 	"regexp"
 	"strings"
 
 	"github.com/arduino/arduino-cli/internal/arduino/utils"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	semver "go.bug.st/relaxed-semver"
@@ -205,13 +207,13 @@ func (p *ProfilePlatformReference) UnmarshalYAML(unmarshal func(interface{}) err
 		return err
 	}
 	if platformID, ok := data["platform"]; !ok {
-		return fmt.Errorf(tr("missing '%s' directive", "platform"))
+		return errors.New(i18n.Tr("missing '%s' directive", "platform"))
 	} else if platformID, platformVersion, ok := parseNameAndVersion(platformID); !ok {
-		return fmt.Errorf(tr("invalid '%s' directive", "platform"))
+		return errors.New(i18n.Tr("invalid '%s' directive", "platform"))
 	} else if c, err := semver.Parse(platformVersion); err != nil {
-		return fmt.Errorf("%s: %w", tr("error parsing version constraints"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("error parsing version constraints"), err)
 	} else if split := strings.SplitN(platformID, ":", 2); len(split) != 2 {
-		return fmt.Errorf("%s: %s", tr("invalid platform identifier"), platformID)
+		return fmt.Errorf("%s: %s", i18n.Tr("invalid platform identifier"), platformID)
 	} else {
 		p.Packager = split[0]
 		p.Architecture = split[1]
@@ -221,7 +223,7 @@ func (p *ProfilePlatformReference) UnmarshalYAML(unmarshal func(interface{}) err
 	if rawIndexURL, ok := data["platform_index_url"]; ok {
 		indexURL, err := url.Parse(rawIndexURL)
 		if err != nil {
-			return fmt.Errorf("%s: %w", tr("invalid platform index URL:"), err)
+			return fmt.Errorf("%s: %w", i18n.Tr("invalid platform index URL:"), err)
 		}
 		p.PlatformIndexURL = indexURL
 	}
@@ -241,9 +243,9 @@ func (l *ProfileLibraryReference) UnmarshalYAML(unmarshal func(interface{}) erro
 		return err
 	}
 	if libName, libVersion, ok := parseNameAndVersion(data); !ok {
-		return fmt.Errorf("%s %s", tr("invalid library directive:"), data)
+		return fmt.Errorf("%s %s", i18n.Tr("invalid library directive:"), data)
 	} else if v, err := semver.Parse(libVersion); err != nil {
-		return fmt.Errorf("%s %w", tr("invalid version:"), err)
+		return fmt.Errorf("%s %w", i18n.Tr("invalid version:"), err)
 	} else {
 		l.Library = libName
 		l.Version = v
diff --git a/internal/arduino/sketch/sketch.go b/internal/arduino/sketch/sketch.go
index 69c0ebdd2e1..2d0c47f35d4 100644
--- a/internal/arduino/sketch/sketch.go
+++ b/internal/arduino/sketch/sketch.go
@@ -42,20 +42,18 @@ type Sketch struct {
 	Project          *Project
 }
 
-var tr = i18n.Tr
-
 // New creates an Sketch instance by reading all the files composing a sketch and grouping them
 // by file type.
 func New(path *paths.Path) (*Sketch, error) {
 	if path == nil {
-		return nil, fmt.Errorf(tr("sketch path is not valid"))
+		return nil, errors.New(i18n.Tr("sketch path is not valid"))
 	}
 
 	path = path.Canonical()
 	if exist, err := path.ExistCheck(); err != nil {
-		return nil, fmt.Errorf("%s: %s", tr("sketch path is not valid"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("sketch path is not valid"), err)
 	} else if !exist {
-		return nil, fmt.Errorf("%s: %s", tr("no such file or directory"), path)
+		return nil, fmt.Errorf("%s: %s", i18n.Tr("no such file or directory"), path)
 	}
 	if globals.MainFileValidExtensions[path.Ext()] && !path.IsDir() {
 		path = path.Parent()
@@ -68,7 +66,7 @@ func New(path *paths.Path) (*Sketch, error) {
 			if mainFile == nil {
 				mainFile = candidateSketchMainFile
 			} else {
-				return nil, errors.New(tr("multiple main sketch files found (%[1]v, %[2]v)",
+				return nil, errors.New(i18n.Tr("multiple main sketch files found (%[1]v, %[2]v)",
 					mainFile,
 					candidateSketchMainFile,
 				))
@@ -76,7 +74,7 @@ func New(path *paths.Path) (*Sketch, error) {
 		}
 	}
 	if mainFile == nil {
-		return nil, fmt.Errorf(tr("main file missing from sketch: %s", path.Join(path.Base()+globals.MainFileValidExtension)))
+		return nil, errors.New(i18n.Tr("main file missing from sketch: %s", path.Join(path.Base()+globals.MainFileValidExtension)))
 	}
 
 	sketch := &Sketch{
@@ -92,7 +90,7 @@ func New(path *paths.Path) (*Sketch, error) {
 	if projectFile := sketch.GetProjectPath(); projectFile.Exist() {
 		prj, err := LoadProjectFile(projectFile)
 		if err != nil {
-			return nil, fmt.Errorf("%s %w", tr("error loading sketch project file:"), err)
+			return nil, fmt.Errorf("%s %w", i18n.Tr("error loading sketch project file:"), err)
 		}
 		sketch.Project = prj
 	}
@@ -105,13 +103,9 @@ func New(path *paths.Path) (*Sketch, error) {
 		return nil, err
 	}
 
-	if mainFile == nil {
-		return nil, fmt.Errorf(tr("can't find main Sketch file in %s"), path)
-	}
-
 	sketchFolderFiles, err := sketch.supportedFiles()
 	if err != nil {
-		return nil, fmt.Errorf("%s: %w", tr("reading sketch files"), err)
+		return nil, fmt.Errorf("%s: %w", i18n.Tr("reading sketch files"), err)
 	}
 
 	// Collect files
@@ -140,7 +134,7 @@ func New(path *paths.Path) (*Sketch, error) {
 				sketch.RootFolderFiles.Add(p)
 			}
 		} else {
-			return nil, errors.New(tr("unknown sketch file extension '%s'", ext))
+			return nil, errors.New(i18n.Tr("unknown sketch file extension '%s'", ext))
 		}
 	}
 
@@ -201,7 +195,7 @@ func (s *Sketch) GetProfile(profileName string) (*Profile, error) {
 func (s *Sketch) checkSketchCasing() error {
 	files, err := s.FullPath.ReadDir()
 	if err != nil {
-		return fmt.Errorf("%s: %w", tr("reading files"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("reading files"), err)
 	}
 	files.FilterOutDirs()
 
@@ -282,7 +276,7 @@ type InvalidSketchFolderNameError struct {
 }
 
 func (e *InvalidSketchFolderNameError) Error() string {
-	return tr("no valid sketch found in %[1]s: missing %[2]s", e.SketchFolder, e.SketchFile)
+	return i18n.Tr("no valid sketch found in %[1]s: missing %[2]s", e.SketchFolder, e.SketchFile)
 }
 
 // DefaultBuildPath generates the default build directory for a given sketch.
diff --git a/internal/arduino/sketch/yaml.go b/internal/arduino/sketch/yaml.go
index 952b200c225..96dcf277838 100644
--- a/internal/arduino/sketch/yaml.go
+++ b/internal/arduino/sketch/yaml.go
@@ -16,9 +16,11 @@
 package sketch
 
 import (
+	"errors"
 	"fmt"
 	"strings"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/go-paths-helper"
 	"gopkg.in/yaml.v3"
 )
@@ -75,15 +77,15 @@ func updateOrAddYamlRootEntry(path *paths.Path, key, newValue string) error {
 	dstYaml := []byte(strings.Join(srcYaml, fmt.Sprintln()) + fmt.Sprintln())
 	var dst interface{}
 	if err := yaml.Unmarshal(dstYaml, &dst); err != nil {
-		return fmt.Errorf("%s: %w", tr("could not update sketch project file"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("could not update sketch project file"), err)
 	}
 	dstMap, ok := dst.(map[string]interface{})
 	if !ok {
-		return fmt.Errorf(tr("could not update sketch project file"))
+		return errors.New(i18n.Tr("could not update sketch project file"))
 	}
 	writtenValue, notRemoved := dstMap[key]
 	if (newValue == "" && notRemoved) || (newValue != "" && newValue != writtenValue) {
-		return fmt.Errorf(tr("could not update sketch project file"))
+		return errors.New(i18n.Tr("could not update sketch project file"))
 	}
 
 	// Write back the updated YAML
diff --git a/internal/cli/arguments/arguments.go b/internal/cli/arguments/arguments.go
index ef8a1596d8f..2d5077dbf7a 100644
--- a/internal/cli/arguments/arguments.go
+++ b/internal/cli/arguments/arguments.go
@@ -23,8 +23,6 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // CheckFlagsConflicts is a helper function useful to report errors when more than one conflicting flag is used
 func CheckFlagsConflicts(command *cobra.Command, flagNames ...string) {
 	for _, flagName := range flagNames {
@@ -33,7 +31,7 @@ func CheckFlagsConflicts(command *cobra.Command, flagNames ...string) {
 		}
 	}
 	flags := "--" + strings.Join(flagNames, ", --")
-	msg := tr("Can't use the following flags together: %s", flags)
+	msg := i18n.Tr("Can't use the following flags together: %s", flags)
 	feedback.Fatal(msg, feedback.ErrBadArgument)
 }
 
@@ -44,7 +42,7 @@ func CheckFlagsMandatory(command *cobra.Command, flagNames ...string) {
 			continue
 		}
 		flags := "--" + strings.Join(flagNames, ", --")
-		msg := tr("Flag %[1]s is mandatory when used in conjunction with: %[2]s", "--"+flagName, flags)
+		msg := i18n.Tr("Flag %[1]s is mandatory when used in conjunction with: %[2]s", "--"+flagName, flags)
 		feedback.Fatal(msg, feedback.ErrBadArgument)
 	}
 }
diff --git a/internal/cli/arguments/discovery_timeout.go b/internal/cli/arguments/discovery_timeout.go
index 140c37fcef8..c63791f64d9 100644
--- a/internal/cli/arguments/discovery_timeout.go
+++ b/internal/cli/arguments/discovery_timeout.go
@@ -18,6 +18,7 @@ package arguments
 import (
 	"time"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/spf13/cobra"
 )
 
@@ -28,7 +29,7 @@ type DiscoveryTimeout struct {
 
 // AddToCommand adds the flags used to set fqbn to the specified Command
 func (d *DiscoveryTimeout) AddToCommand(cmd *cobra.Command) {
-	cmd.Flags().DurationVar(&d.timeout, "discovery-timeout", time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m"))
+	cmd.Flags().DurationVar(&d.timeout, "discovery-timeout", time.Second, i18n.Tr("Max time to wait for port discovery, e.g.: 30s, 1m"))
 }
 
 // Get returns the timeout
diff --git a/internal/cli/arguments/fqbn.go b/internal/cli/arguments/fqbn.go
index e1cb338c77d..a721c85d19f 100644
--- a/internal/cli/arguments/fqbn.go
+++ b/internal/cli/arguments/fqbn.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/spf13/cobra"
 )
@@ -35,12 +36,12 @@ type Fqbn struct {
 
 // AddToCommand adds the flags used to set fqbn to the specified Command
 func (f *Fqbn) AddToCommand(cmd *cobra.Command, srv rpc.ArduinoCoreServiceServer) {
-	cmd.Flags().StringVarP(&f.fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
+	cmd.Flags().StringVarP(&f.fqbn, "fqbn", "b", "", i18n.Tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
 	cmd.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		return GetInstalledBoards(cmd.Context(), srv), cobra.ShellCompDirectiveDefault
 	})
 	cmd.Flags().StringSliceVar(&f.boardOptions, "board-options", []string{},
-		tr("List of board options separated by commas. Or can be used multiple times for multiple options."))
+		i18n.Tr("List of board options separated by commas. Or can be used multiple times for multiple options."))
 }
 
 // String returns the fqbn with the board options if there are any
@@ -88,7 +89,7 @@ func CalculateFQBNAndPort(ctx context.Context, portArgs *Port, fqbnArg *Fqbn, in
 
 	port, err := portArgs.GetPort(ctx, instance, srv, defaultAddress, defaultProtocol)
 	if err != nil {
-		feedback.Fatal(tr("Error getting port metadata: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error getting port metadata: %v", err), feedback.ErrGeneric)
 	}
 	return fqbn, port
 }
diff --git a/internal/cli/arguments/port.go b/internal/cli/arguments/port.go
index 1d138043fbc..a9b94457e6b 100644
--- a/internal/cli/arguments/port.go
+++ b/internal/cli/arguments/port.go
@@ -17,13 +17,14 @@ package arguments
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"time"
 
 	"github.com/arduino/arduino-cli/commands"
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	f "github.com/arduino/arduino-cli/internal/algorithms"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -40,11 +41,11 @@ type Port struct {
 
 // AddToCommand adds the flags used to set port and protocol to the specified Command
 func (p *Port) AddToCommand(cmd *cobra.Command, srv rpc.ArduinoCoreServiceServer) {
-	cmd.Flags().StringVarP(&p.address, "port", "p", "", tr("Upload port address, e.g.: COM3 or /dev/ttyACM2"))
+	cmd.Flags().StringVarP(&p.address, "port", "p", "", i18n.Tr("Upload port address, e.g.: COM3 or /dev/ttyACM2"))
 	cmd.RegisterFlagCompletionFunc("port", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		return f.Map(GetAvailablePorts(cmd.Context(), srv), (*rpc.Port).GetAddress), cobra.ShellCompDirectiveDefault
 	})
-	cmd.Flags().StringVarP(&p.protocol, "protocol", "l", "", tr("Upload port protocol, e.g: serial"))
+	cmd.Flags().StringVarP(&p.protocol, "protocol", "l", "", i18n.Tr("Upload port protocol, e.g: serial"))
 	cmd.RegisterFlagCompletionFunc("protocol", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		return f.Map(GetAvailablePorts(cmd.Context(), srv), (*rpc.Port).GetProtocol), cobra.ShellCompDirectiveDefault
 	})
@@ -118,7 +119,7 @@ func (p *Port) GetPort(ctx context.Context, instance *rpc.Instance, srv rpc.Ardu
 					Protocol: "serial",
 				}, nil
 			}
-			return nil, fmt.Errorf(tr("port not found: %[1]s %[2]s"), address, protocol)
+			return nil, errors.New(i18n.Tr("port not found: %[1]s %[2]s", address, protocol))
 		}
 	}
 }
@@ -137,7 +138,7 @@ func (p *Port) DetectFQBN(ctx context.Context, inst *rpc.Instance, srv rpc.Ardui
 		Timeout:  p.timeout.Get().Milliseconds(),
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error during FQBN detection: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error during FQBN detection: %v", err), feedback.ErrGeneric)
 	}
 	for _, detectedPort := range detectedPorts.GetPorts() {
 		port := detectedPort.GetPort()
diff --git a/internal/cli/arguments/pre_post_script.go b/internal/cli/arguments/pre_post_script.go
index ec96711dfa4..8d492ec06c8 100644
--- a/internal/cli/arguments/pre_post_script.go
+++ b/internal/cli/arguments/pre_post_script.go
@@ -17,6 +17,7 @@ package arguments
 
 import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 )
@@ -34,10 +35,10 @@ type PrePostScriptsFlags struct {
 // AddToCommand adds flags that can be used to force running or skipping
 // of post installation scripts
 func (p *PrePostScriptsFlags) AddToCommand(cmd *cobra.Command) {
-	cmd.Flags().BoolVar(&p.runPostInstall, "run-post-install", false, tr("Force run of post-install scripts (if the CLI is not running interactively)."))
-	cmd.Flags().BoolVar(&p.skipPostInstall, "skip-post-install", false, tr("Force skip of post-install scripts (if the CLI is running interactively)."))
-	cmd.Flags().BoolVar(&p.runPreUninstall, "run-pre-uninstall", false, tr("Force run of pre-uninstall scripts (if the CLI is not running interactively)."))
-	cmd.Flags().BoolVar(&p.skipPreUninstall, "skip-pre-uninstall", false, tr("Force skip of pre-uninstall scripts (if the CLI is running interactively)."))
+	cmd.Flags().BoolVar(&p.runPostInstall, "run-post-install", false, i18n.Tr("Force run of post-install scripts (if the CLI is not running interactively)."))
+	cmd.Flags().BoolVar(&p.skipPostInstall, "skip-post-install", false, i18n.Tr("Force skip of post-install scripts (if the CLI is running interactively)."))
+	cmd.Flags().BoolVar(&p.runPreUninstall, "run-pre-uninstall", false, i18n.Tr("Force run of pre-uninstall scripts (if the CLI is not running interactively)."))
+	cmd.Flags().BoolVar(&p.skipPreUninstall, "skip-pre-uninstall", false, i18n.Tr("Force skip of pre-uninstall scripts (if the CLI is running interactively)."))
 }
 
 // GetRunPostInstall returns the run-post-install flag value
diff --git a/internal/cli/arguments/profiles.go b/internal/cli/arguments/profiles.go
index 59d56656fa6..be7fd6a2acd 100644
--- a/internal/cli/arguments/profiles.go
+++ b/internal/cli/arguments/profiles.go
@@ -16,6 +16,7 @@
 package arguments
 
 import (
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/spf13/cobra"
 )
@@ -29,7 +30,7 @@ type Profile struct {
 
 // AddToCommand adds the flags used to set fqbn to the specified Command
 func (f *Profile) AddToCommand(cmd *cobra.Command, srv rpc.ArduinoCoreServiceServer) {
-	cmd.Flags().StringVarP(&f.profile, "profile", "m", "", tr("Sketch profile to use"))
+	cmd.Flags().StringVarP(&f.profile, "profile", "m", "", i18n.Tr("Sketch profile to use"))
 	cmd.RegisterFlagCompletionFunc("profile", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		var sketchProfile string
 		if len(args) > 0 {
diff --git a/internal/cli/arguments/programmer.go b/internal/cli/arguments/programmer.go
index 6f590b85164..a077adc1b5c 100644
--- a/internal/cli/arguments/programmer.go
+++ b/internal/cli/arguments/programmer.go
@@ -18,6 +18,7 @@ package arguments
 import (
 	"context"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/spf13/cobra"
 )
@@ -31,7 +32,7 @@ type Programmer struct {
 
 // AddToCommand adds the flags used to set the programmer to the specified Command
 func (p *Programmer) AddToCommand(cmd *cobra.Command, srv rpc.ArduinoCoreServiceServer) {
-	cmd.Flags().StringVarP(&p.programmer, "programmer", "P", "", tr("Programmer to use, e.g: atmel_ice"))
+	cmd.Flags().StringVarP(&p.programmer, "programmer", "P", "", i18n.Tr("Programmer to use, e.g: atmel_ice"))
 	cmd.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		return GetInstalledProgrammers(cmd.Context(), srv), cobra.ShellCompDirectiveDefault
 	})
diff --git a/internal/cli/arguments/reference.go b/internal/cli/arguments/reference.go
index 613a16912fa..8c09b532a72 100644
--- a/internal/cli/arguments/reference.go
+++ b/internal/cli/arguments/reference.go
@@ -17,11 +17,12 @@ package arguments
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"strings"
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 )
@@ -65,30 +66,30 @@ func ParseReference(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg s
 	logrus.Infof("Parsing reference %s", arg)
 	ret := &Reference{}
 	if arg == "" {
-		return nil, fmt.Errorf(tr("invalid empty core argument"))
+		return nil, errors.New(i18n.Tr("invalid empty core argument"))
 	}
 
 	toks := strings.SplitN(arg, "@", 2)
 	if toks[0] == "" {
-		return nil, fmt.Errorf(tr("invalid empty core reference '%s'"), arg)
+		return nil, errors.New(i18n.Tr("invalid empty core reference '%s'", arg))
 	}
 	ret.PackageName = toks[0]
 	if len(toks) > 1 {
 		if toks[1] == "" {
-			return nil, fmt.Errorf(tr("invalid empty core version: '%s'"), arg)
+			return nil, errors.New(i18n.Tr("invalid empty core version: '%s'", arg))
 		}
 		ret.Version = toks[1]
 	}
 
 	toks = strings.Split(ret.PackageName, ":")
 	if len(toks) != 2 {
-		return nil, fmt.Errorf(tr("invalid item %s"), arg)
+		return nil, errors.New(i18n.Tr("invalid item %s", arg))
 	}
 	if toks[0] == "" {
-		return nil, fmt.Errorf(tr("invalid empty core name '%s'"), arg)
+		return nil, errors.New(i18n.Tr("invalid empty core name '%s'", arg))
 	}
 	if toks[1] == "" {
-		return nil, fmt.Errorf(tr("invalid empty core architecture '%s'"), arg)
+		return nil, errors.New(i18n.Tr("invalid empty core architecture '%s'", arg))
 	}
 	ret.PackageName = toks[0]
 	ret.Architecture = toks[1]
diff --git a/internal/cli/arguments/show_properties.go b/internal/cli/arguments/show_properties.go
index ecf3108b639..723ea94df91 100644
--- a/internal/cli/arguments/show_properties.go
+++ b/internal/cli/arguments/show_properties.go
@@ -16,8 +16,9 @@
 package arguments
 
 import (
-	"fmt"
+	"errors"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/spf13/cobra"
 )
 
@@ -48,7 +49,7 @@ func (p *ShowProperties) Get() (ShowPropertiesMode, error) {
 	case "expanded":
 		return ShowPropertiesExpanded, nil
 	default:
-		return ShowPropertiesDisabled, fmt.Errorf(tr("invalid option '%s'.", p.arg))
+		return ShowPropertiesDisabled, errors.New(i18n.Tr("invalid option '%s'.", p.arg))
 	}
 }
 
@@ -56,7 +57,7 @@ func (p *ShowProperties) Get() (ShowPropertiesMode, error) {
 func (p *ShowProperties) AddToCommand(command *cobra.Command) {
 	command.Flags().StringVar(&p.arg,
 		"show-properties", "disabled",
-		tr(`Show build properties. The properties are expanded, use "--show-properties=unexpanded" if you want them exactly as they are defined.`),
+		i18n.Tr(`Show build properties. The properties are expanded, use "--show-properties=unexpanded" if you want them exactly as they are defined.`),
 	)
 	command.Flags().Lookup("show-properties").NoOptDefVal = "expanded" // default if the flag is present with no value
 }
diff --git a/internal/cli/arguments/sketch.go b/internal/cli/arguments/sketch.go
index e946c4fd6a2..8a912e0dbc8 100644
--- a/internal/cli/arguments/sketch.go
+++ b/internal/cli/arguments/sketch.go
@@ -20,6 +20,7 @@ import (
 
 	f "github.com/arduino/arduino-cli/internal/algorithms"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -33,7 +34,7 @@ func InitSketchPath(path string) (sketchPath *paths.Path) {
 	} else {
 		wd, err := paths.Getwd()
 		if err != nil {
-			feedback.Fatal(tr("Couldn't get current working directory: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Couldn't get current working directory: %v", err), feedback.ErrGeneric)
 		}
 		logrus.Infof("Reading sketch from dir: %s", wd)
 		sketchPath = wd
diff --git a/internal/cli/board/attach.go b/internal/cli/board/attach.go
index c8b8dca3e28..871f0bbd5dc 100644
--- a/internal/cli/board/attach.go
+++ b/internal/cli/board/attach.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/spf13/cobra"
 )
@@ -31,9 +32,9 @@ func initAttachCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var fqbn arguments.Fqbn
 	var programmer arguments.Programmer
 	attachCommand := &cobra.Command{
-		Use:   fmt.Sprintf("attach [-p <%s>] [-b <%s>] [-P <%s>] [%s]", tr("port"), tr("FQBN"), tr("programmer"), tr("sketchPath")),
-		Short: tr("Attaches a sketch to a board."),
-		Long:  tr("Sets the default values for port and FQBN. If no port, FQBN or programmer are specified, the current default port, FQBN and programmer are displayed."),
+		Use:   fmt.Sprintf("attach [-p <%s>] [-b <%s>] [-P <%s>] [%s]", i18n.Tr("port"), i18n.Tr("FQBN"), i18n.Tr("programmer"), i18n.Tr("sketchPath")),
+		Short: i18n.Tr("Attaches a sketch to a board."),
+		Long:  i18n.Tr("Sets the default values for port and FQBN. If no port, FQBN or programmer are specified, the current default port, FQBN and programmer are displayed."),
 		Example: "  " + os.Args[0] + " board attach -p /dev/ttyACM0\n" +
 			"  " + os.Args[0] + " board attach -p /dev/ttyACM0 HelloWorld\n" +
 			"  " + os.Args[0] + " board attach -b arduino:samd:mkr1000" +
@@ -108,10 +109,10 @@ func (b *boardAttachResult) Data() interface{} {
 
 func (b *boardAttachResult) String() string {
 	if b.Port == nil && b.Fqbn == "" && b.Programmer == "" {
-		return tr("No default port, FQBN or programmer set")
+		return i18n.Tr("No default port, FQBN or programmer set")
 	}
-	res := fmt.Sprintf("%s: %s\n", tr("Default port set to"), b.Port)
-	res += fmt.Sprintf("%s: %s\n", tr("Default FQBN set to"), b.Fqbn)
-	res += fmt.Sprintf("%s: %s\n", tr("Default programmer set to"), b.Programmer)
+	res := fmt.Sprintf("%s: %s\n", i18n.Tr("Default port set to"), b.Port)
+	res += fmt.Sprintf("%s: %s\n", i18n.Tr("Default FQBN set to"), b.Fqbn)
+	res += fmt.Sprintf("%s: %s\n", i18n.Tr("Default programmer set to"), b.Programmer)
 	return res
 }
diff --git a/internal/cli/board/board.go b/internal/cli/board/board.go
index f07ff8c0ac3..23bc050f071 100644
--- a/internal/cli/board/board.go
+++ b/internal/cli/board/board.go
@@ -23,15 +23,13 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `board` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	boardCommand := &cobra.Command{
 		Use:   "board",
-		Short: tr("Arduino board commands."),
-		Long:  tr("Arduino board commands."),
-		Example: "  # " + tr("Lists all connected boards.") + "\n" +
+		Short: i18n.Tr("Arduino board commands."),
+		Long:  i18n.Tr("Arduino board commands."),
+		Example: "  # " + i18n.Tr("Lists all connected boards.") + "\n" +
 			"  " + os.Args[0] + " board list",
 	}
 
diff --git a/internal/cli/board/details.go b/internal/cli/board/details.go
index 4e7d8579f19..5023050c579 100644
--- a/internal/cli/board/details.go
+++ b/internal/cli/board/details.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/fatih/color"
 	"github.com/sirupsen/logrus"
@@ -37,9 +38,9 @@ func initDetailsCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var fqbn arguments.Fqbn
 	var showProperties arguments.ShowProperties
 	var detailsCommand = &cobra.Command{
-		Use:     fmt.Sprintf("details -b <%s>", tr("FQBN")),
-		Short:   tr("Print details about a board."),
-		Long:    tr("Show information about a board, in particular if the board has options to be specified in the FQBN."),
+		Use:     fmt.Sprintf("details -b <%s>", i18n.Tr("FQBN")),
+		Short:   i18n.Tr("Print details about a board."),
+		Long:    i18n.Tr("Show information about a board, in particular if the board has options to be specified in the FQBN."),
 		Example: "  " + os.Args[0] + " board details -b arduino:avr:nano",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
@@ -48,8 +49,8 @@ func initDetailsCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	}
 
 	fqbn.AddToCommand(detailsCommand, srv)
-	detailsCommand.Flags().BoolVarP(&showFullDetails, "full", "f", false, tr("Show full board details"))
-	detailsCommand.Flags().BoolVarP(&listProgrammers, "list-programmers", "", false, tr("Show list of available programmers"))
+	detailsCommand.Flags().BoolVarP(&showFullDetails, "full", "f", false, i18n.Tr("Show full board details"))
+	detailsCommand.Flags().BoolVarP(&listProgrammers, "list-programmers", "", false, i18n.Tr("Show list of available programmers"))
 	detailsCommand.MarkFlagRequired("fqbn")
 	showProperties.AddToCommand(detailsCommand)
 	return detailsCommand
@@ -70,7 +71,7 @@ func runDetailsCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, fq
 		DoNotExpandBuildProperties: showPropertiesMode == arguments.ShowPropertiesUnexpanded,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error getting board details: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error getting board details: %v", err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(detailsResult{
@@ -107,7 +108,7 @@ func (dr detailsResult) String() string {
 
 	if dr.listProgrammers {
 		t := table.New()
-		t.AddRow(tr("Id"), tr("Programmer name"))
+		t.AddRow(i18n.Tr("Id"), i18n.Tr("Programmer name"))
 		for _, programmer := range details.Programmers {
 			t.AddRow(programmer.Id, programmer.Name)
 		}
@@ -135,13 +136,13 @@ func (dr detailsResult) String() string {
 	}
 
 	t.SetColumnWidthMode(1, table.Average)
-	t.AddRow(tr("Board name:"), details.Name)
-	t.AddRow(tr("FQBN:"), details.Fqbn)
-	addIfNotEmpty(tr("Board version:"), details.Version)
+	t.AddRow(i18n.Tr("Board name:"), details.Name)
+	t.AddRow(i18n.Tr("FQBN:"), details.Fqbn)
+	addIfNotEmpty(i18n.Tr("Board version:"), details.Version)
 
 	if details.Official {
 		t.AddRow() // get some space from above
-		t.AddRow(tr("Official Arduino board:"),
+		t.AddRow(i18n.Tr("Official Arduino board:"),
 			table.NewCell("✔", color.New(color.FgGreen)))
 	}
 
@@ -150,7 +151,7 @@ func (dr detailsResult) String() string {
 			continue
 		}
 		t.AddRow() // get some space from above
-		header := tr("Identification properties:")
+		header := i18n.Tr("Identification properties:")
 		keys := idp.Properties.Keys()
 		for _, k := range keys {
 			t.AddRow(header, k+"="+idp.Properties.Get(k))
@@ -159,35 +160,35 @@ func (dr detailsResult) String() string {
 	}
 
 	t.AddRow() // get some space from above
-	addIfNotEmpty(tr("Package name:"), details.Package.Name)
-	addIfNotEmpty(tr("Package maintainer:"), details.Package.Maintainer)
-	addIfNotEmpty(tr("Package URL:"), details.Package.Url)
-	addIfNotEmpty(tr("Package website:"), details.Package.WebsiteUrl)
-	addIfNotEmpty(tr("Package online help:"), details.Package.Help.Online)
+	addIfNotEmpty(i18n.Tr("Package name:"), details.Package.Name)
+	addIfNotEmpty(i18n.Tr("Package maintainer:"), details.Package.Maintainer)
+	addIfNotEmpty(i18n.Tr("Package URL:"), details.Package.Url)
+	addIfNotEmpty(i18n.Tr("Package website:"), details.Package.WebsiteUrl)
+	addIfNotEmpty(i18n.Tr("Package online help:"), details.Package.Help.Online)
 
 	t.AddRow() // get some space from above
-	addIfNotEmpty(tr("Platform name:"), details.Platform.Name)
-	addIfNotEmpty(tr("Platform category:"), details.Platform.Category)
-	addIfNotEmpty(tr("Platform architecture:"), details.Platform.Architecture)
-	addIfNotEmpty(tr("Platform URL:"), details.Platform.Url)
-	addIfNotEmpty(tr("Platform file name:"), details.Platform.ArchiveFilename)
+	addIfNotEmpty(i18n.Tr("Platform name:"), details.Platform.Name)
+	addIfNotEmpty(i18n.Tr("Platform category:"), details.Platform.Category)
+	addIfNotEmpty(i18n.Tr("Platform architecture:"), details.Platform.Architecture)
+	addIfNotEmpty(i18n.Tr("Platform URL:"), details.Platform.Url)
+	addIfNotEmpty(i18n.Tr("Platform file name:"), details.Platform.ArchiveFilename)
 	if details.Platform.Size != 0 {
-		addIfNotEmpty(tr("Platform size (bytes):"), fmt.Sprint(details.Platform.Size))
+		addIfNotEmpty(i18n.Tr("Platform size (bytes):"), fmt.Sprint(details.Platform.Size))
 	}
-	addIfNotEmpty(tr("Platform checksum:"), details.Platform.Checksum)
+	addIfNotEmpty(i18n.Tr("Platform checksum:"), details.Platform.Checksum)
 
 	t.AddRow() // get some space from above
 
 	tab.SetColumnWidthMode(1, table.Average)
 	for _, tool := range details.ToolsDependencies {
-		tab.AddRow(tr("Required tool:"), tool.Packager+":"+tool.Name, tool.Version)
+		tab.AddRow(i18n.Tr("Required tool:"), tool.Packager+":"+tool.Name, tool.Version)
 		if dr.showFullDetails {
 			for _, sys := range tool.Systems {
-				tab.AddRow("", tr("OS:"), sys.Host)
-				tab.AddRow("", tr("File:"), sys.ArchiveFilename)
-				tab.AddRow("", tr("Size (bytes):"), fmt.Sprint(sys.Size))
-				tab.AddRow("", tr("Checksum:"), sys.Checksum)
-				tab.AddRow("", tr("URL:"), sys.Url)
+				tab.AddRow("", i18n.Tr("OS:"), sys.Host)
+				tab.AddRow("", i18n.Tr("File:"), sys.ArchiveFilename)
+				tab.AddRow("", i18n.Tr("Size (bytes):"), fmt.Sprint(sys.Size))
+				tab.AddRow("", i18n.Tr("Checksum:"), sys.Checksum)
+				tab.AddRow("", i18n.Tr("URL:"), sys.Url)
 				tab.AddRow() // get some space from above
 			}
 		}
@@ -196,7 +197,7 @@ func (dr detailsResult) String() string {
 	green := color.New(color.FgGreen)
 	tab.AddRow() // get some space from above
 	for _, option := range details.ConfigOptions {
-		tab.AddRow(tr("Option:"), option.OptionLabel, "", option.Option)
+		tab.AddRow(i18n.Tr("Option:"), option.OptionLabel, "", option.Option)
 		for _, value := range option.Values {
 			if value.Selected {
 				tab.AddRow("",
@@ -212,7 +213,7 @@ func (dr detailsResult) String() string {
 		}
 	}
 
-	tab.AddRow(tr("Programmers:"), tr("ID"), tr("Name"), "")
+	tab.AddRow(i18n.Tr("Programmers:"), i18n.Tr("ID"), i18n.Tr("Name"), "")
 	for _, programmer := range details.Programmers {
 		if programmer.Id == details.DefaultProgrammerID {
 			tab.AddRow("", table.NewCell(programmer.Id, green), table.NewCell(programmer.Name, green), table.NewCell("✔ (default)", green))
diff --git a/internal/cli/board/list.go b/internal/cli/board/list.go
index 20001f2ad82..ffc49431d21 100644
--- a/internal/cli/board/list.go
+++ b/internal/cli/board/list.go
@@ -30,6 +30,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -41,8 +42,8 @@ func initListCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var fqbn arguments.Fqbn
 	listCommand := &cobra.Command{
 		Use:     "list",
-		Short:   tr("List connected boards."),
-		Long:    tr("Detects and displays a list of boards connected to the current computer."),
+		Short:   i18n.Tr("List connected boards."),
+		Long:    i18n.Tr("Detects and displays a list of boards connected to the current computer."),
 		Example: "  " + os.Args[0] + " board list --discovery-timeout 10s",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
@@ -52,7 +53,7 @@ func initListCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 
 	timeoutArg.AddToCommand(listCommand)
 	fqbn.AddToCommand(listCommand, srv)
-	listCommand.Flags().BoolVarP(&watch, "watch", "w", false, tr("Command keeps running and prints list of connected boards whenever there is a change."))
+	listCommand.Flags().BoolVarP(&watch, "watch", "w", false, i18n.Tr("Command keeps running and prints list of connected boards whenever there is a change."))
 	return listCommand
 }
 
@@ -76,13 +77,13 @@ func runListCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, watch
 	discoveryErrors := list.GetWarnings()
 	var invalidFQBNErr *cmderrors.InvalidFQBNError
 	if errors.As(err, &invalidFQBNErr) {
-		feedback.Fatal(tr(err.Error()), feedback.ErrBadArgument)
+		feedback.Fatal(err.Error(), feedback.ErrBadArgument)
 	}
 	if err != nil {
-		feedback.Warning(tr("Error detecting boards: %v", err))
+		feedback.Warning(i18n.Tr("Error detecting boards: %v", err))
 	}
 	for _, err := range discoveryErrors {
-		feedback.Warning(tr("Error starting discovery: %v", err))
+		feedback.Warning(i18n.Tr("Error starting discovery: %v", err))
 	}
 
 	feedback.PrintResult(listResult{result.NewDetectedPorts(ports)})
@@ -92,13 +93,13 @@ func watchList(ctx context.Context, inst *rpc.Instance, srv rpc.ArduinoCoreServi
 	stream, eventsChan := commands.BoardListWatchProxyToChan(ctx)
 	err := srv.BoardListWatch(&rpc.BoardListWatchRequest{Instance: inst}, stream)
 	if err != nil {
-		feedback.Fatal(tr("Error detecting boards: %v", err), feedback.ErrNetwork)
+		feedback.Fatal(i18n.Tr("Error detecting boards: %v", err), feedback.ErrNetwork)
 	}
 
 	// This is done to avoid printing the header each time a new event is received
 	if feedback.GetFormat() == feedback.Text {
 		t := table.New()
-		t.SetHeader(tr("Port"), tr("Type"), tr("Event"), tr("Board Name"), tr("FQBN"), tr("Core"))
+		t.SetHeader(i18n.Tr("Port"), i18n.Tr("Type"), i18n.Tr("Event"), i18n.Tr("Board Name"), i18n.Tr("FQBN"), i18n.Tr("Core"))
 		feedback.Print(t.Render())
 	}
 
@@ -126,7 +127,7 @@ func (dr listResult) Data() interface{} {
 
 func (dr listResult) String() string {
 	if len(dr.Ports) == 0 {
-		return tr("No boards found.")
+		return i18n.Tr("No boards found.")
 	}
 
 	sort.Slice(dr.Ports, func(i, j int) bool {
@@ -136,7 +137,7 @@ func (dr listResult) String() string {
 	})
 
 	t := table.New()
-	t.SetHeader(tr("Port"), tr("Protocol"), tr("Type"), tr("Board Name"), tr("FQBN"), tr("Core"))
+	t.SetHeader(i18n.Tr("Port"), i18n.Tr("Protocol"), i18n.Tr("Type"), i18n.Tr("Board Name"), i18n.Tr("FQBN"), i18n.Tr("Core"))
 	for _, detectedPort := range dr.Ports {
 		port := detectedPort.Port
 		protocol := port.Protocol
@@ -168,7 +169,7 @@ func (dr listResult) String() string {
 				protocol = ""
 			}
 		} else {
-			board := tr("Unknown")
+			board := i18n.Tr("Unknown")
 			fqbn := ""
 			coreName := ""
 			t.AddRow(address, protocol, protocolLabel, board, fqbn, coreName)
@@ -192,8 +193,8 @@ func (dr watchEventResult) String() string {
 	t := table.New()
 
 	event := map[string]string{
-		"add":    tr("Connected"),
-		"remove": tr("Disconnected"),
+		"add":    i18n.Tr("Connected"),
+		"remove": i18n.Tr("Disconnected"),
 	}[dr.Type]
 
 	address := fmt.Sprintf("%s://%s", dr.Port.Protocol, dr.Port.Address)
diff --git a/internal/cli/board/listall.go b/internal/cli/board/listall.go
index 55381ba2ffc..aeb46c84061 100644
--- a/internal/cli/board/listall.go
+++ b/internal/cli/board/listall.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -34,9 +35,9 @@ var showHiddenBoard bool
 
 func initListAllCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var listAllCommand = &cobra.Command{
-		Use:   fmt.Sprintf("listall [%s]", tr("boardname")),
-		Short: tr("List all known boards and their corresponding FQBN."),
-		Long: tr(`List all boards that have the support platform installed. You can search
+		Use:   fmt.Sprintf("listall [%s]", i18n.Tr("boardname")),
+		Short: i18n.Tr("List all known boards and their corresponding FQBN."),
+		Long: i18n.Tr(`List all boards that have the support platform installed. You can search
 for a specific board if you specify the board name`),
 		Example: "" +
 			"  " + os.Args[0] + " board listall\n" +
@@ -46,7 +47,7 @@ for a specific board if you specify the board name`),
 			runListAllCommand(cmd.Context(), args, srv)
 		},
 	}
-	listAllCommand.Flags().BoolVarP(&showHiddenBoard, "show-hidden", "a", false, tr("Show also boards marked as 'hidden' in the platform"))
+	listAllCommand.Flags().BoolVarP(&showHiddenBoard, "show-hidden", "a", false, i18n.Tr("Show also boards marked as 'hidden' in the platform"))
 	return listAllCommand
 }
 
@@ -62,7 +63,7 @@ func runListAllCommand(ctx context.Context, args []string, srv rpc.ArduinoCoreSe
 		IncludeHiddenBoards: showHiddenBoard,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error listing boards: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error listing boards: %v", err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(resultAll{result.NewBoardListAllResponse(list)})
@@ -80,7 +81,7 @@ func (dr resultAll) Data() interface{} {
 
 func (dr resultAll) String() string {
 	t := table.New()
-	t.SetHeader(tr("Board Name"), tr("FQBN"), "")
+	t.SetHeader(i18n.Tr("Board Name"), i18n.Tr("FQBN"), "")
 
 	if dr.list == nil || len(dr.list.Boards) == 0 {
 		return t.Render()
@@ -93,7 +94,7 @@ func (dr resultAll) String() string {
 	for _, item := range dr.list.Boards {
 		hidden := ""
 		if item.IsHidden {
-			hidden = tr("(hidden)")
+			hidden = i18n.Tr("(hidden)")
 		}
 		t.AddRow(item.Name, item.Fqbn, hidden)
 	}
diff --git a/internal/cli/board/search.go b/internal/cli/board/search.go
index 42b85785788..5df42f6009c 100644
--- a/internal/cli/board/search.go
+++ b/internal/cli/board/search.go
@@ -26,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -33,9 +34,9 @@ import (
 
 func initSearchCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var searchCommand = &cobra.Command{
-		Use:   fmt.Sprintf("search [%s]", tr("boardname")),
-		Short: tr("Search for a board in the Boards Manager."),
-		Long:  tr(`Search for a board in the Boards Manager using the specified keywords.`),
+		Use:   fmt.Sprintf("search [%s]", i18n.Tr("boardname")),
+		Short: i18n.Tr("Search for a board in the Boards Manager."),
+		Long:  i18n.Tr(`Search for a board in the Boards Manager using the specified keywords.`),
 		Example: "" +
 			"  " + os.Args[0] + " board search\n" +
 			"  " + os.Args[0] + " board search zero",
@@ -44,7 +45,7 @@ func initSearchCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 			runSearchCommand(cmd.Context(), srv, args)
 		},
 	}
-	searchCommand.Flags().BoolVarP(&showHiddenBoard, "show-hidden", "a", false, tr("Show also boards marked as 'hidden' in the platform"))
+	searchCommand.Flags().BoolVarP(&showHiddenBoard, "show-hidden", "a", false, i18n.Tr("Show also boards marked as 'hidden' in the platform"))
 	return searchCommand
 }
 
@@ -59,7 +60,7 @@ func runSearchCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 		IncludeHiddenBoards: showHiddenBoard,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error searching boards: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error searching boards: %v", err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(searchResults{result.NewBoardListItems(res.GetBoards())})
@@ -81,7 +82,7 @@ func (r searchResults) String() string {
 	}
 
 	t := table.New()
-	t.SetHeader(tr("Board Name"), tr("FQBN"), tr("Platform ID"), "")
+	t.SetHeader(i18n.Tr("Board Name"), i18n.Tr("FQBN"), i18n.Tr("Platform ID"), "")
 
 	sort.Slice(r.Boards, func(i, j int) bool {
 		return r.Boards[i].Name < r.Boards[j].Name
@@ -90,7 +91,7 @@ func (r searchResults) String() string {
 	for _, item := range r.Boards {
 		hidden := ""
 		if item.IsHidden {
-			hidden = tr("(hidden)")
+			hidden = i18n.Tr("(hidden)")
 		}
 		t.AddRow(item.Name, item.Fqbn, item.Platform.Metadata.Id, hidden)
 	}
diff --git a/internal/cli/burnbootloader/burnbootloader.go b/internal/cli/burnbootloader/burnbootloader.go
index 7c8f4c16896..5187036aabc 100644
--- a/internal/cli/burnbootloader/burnbootloader.go
+++ b/internal/cli/burnbootloader/burnbootloader.go
@@ -45,8 +45,8 @@ var (
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	burnBootloaderCommand := &cobra.Command{
 		Use:     "burn-bootloader",
-		Short:   tr("Upload the bootloader."),
-		Long:    tr("Upload the bootloader on the board using an external programmer."),
+		Short:   i18n.Tr("Upload the bootloader."),
+		Long:    i18n.Tr("Upload the bootloader on the board using an external programmer."),
 		Example: "  " + os.Args[0] + " burn-bootloader -b arduino:avr:uno -P atmel_ice",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
@@ -57,9 +57,9 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	fqbn.AddToCommand(burnBootloaderCommand, srv)
 	port.AddToCommand(burnBootloaderCommand, srv)
 	programmer.AddToCommand(burnBootloaderCommand, srv)
-	burnBootloaderCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload."))
-	burnBootloaderCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Turns on verbose mode."))
-	burnBootloaderCommand.Flags().BoolVar(&dryRun, "dry-run", false, tr("Do not perform the actual upload, just log out actions"))
+	burnBootloaderCommand.Flags().BoolVarP(&verify, "verify", "t", false, i18n.Tr("Verify uploaded binary after the upload."))
+	burnBootloaderCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, i18n.Tr("Turns on verbose mode."))
+	burnBootloaderCommand.Flags().BoolVar(&dryRun, "dry-run", false, i18n.Tr("Do not perform the actual upload, just log out actions"))
 	burnBootloaderCommand.Flags().MarkHidden("dry-run")
 
 	return burnBootloaderCommand
@@ -73,7 +73,7 @@ func runBootloaderCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer)
 	// We don't need a Sketch to upload a board's bootloader
 	discoveryPort, err := port.GetPort(ctx, instance, srv, "", "")
 	if err != nil {
-		feedback.Fatal(tr("Error during Upload: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error during Upload: %v", err), feedback.ErrGeneric)
 	}
 
 	stdOut, stdErr, res := feedback.OutputStreams()
@@ -94,7 +94,7 @@ func runBootloaderCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer)
 		if errors.Is(err, &cmderrors.MissingProgrammerError{}) {
 			errcode = feedback.ErrMissingProgrammer
 		}
-		feedback.Fatal(tr("Error during Upload: %v", err), errcode)
+		feedback.Fatal(i18n.Tr("Error during Upload: %v", err), errcode)
 	}
 	feedback.PrintResult(res())
 }
diff --git a/internal/cli/cache/cache.go b/internal/cli/cache/cache.go
index e6b14ebe90d..38b12c3c0fa 100644
--- a/internal/cli/cache/cache.go
+++ b/internal/cli/cache/cache.go
@@ -23,15 +23,13 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `cache` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	cacheCommand := &cobra.Command{
 		Use:   "cache",
-		Short: tr("Arduino cache commands."),
-		Long:  tr("Arduino cache commands."),
-		Example: "# " + tr("Clean caches.") + "\n" +
+		Short: i18n.Tr("Arduino cache commands."),
+		Long:  i18n.Tr("Arduino cache commands."),
+		Example: "# " + i18n.Tr("Clean caches.") + "\n" +
 			" " + os.Args[0] + " cache clean\n\n",
 	}
 
diff --git a/internal/cli/cache/clean.go b/internal/cli/cache/clean.go
index 184d2e65b90..d5bfead5ac3 100644
--- a/internal/cli/cache/clean.go
+++ b/internal/cli/cache/clean.go
@@ -20,6 +20,7 @@ import (
 	"os"
 
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -28,8 +29,8 @@ import (
 func initCleanCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	cleanCommand := &cobra.Command{
 		Use:     "clean",
-		Short:   tr("Delete Boards/Library Manager download cache."),
-		Long:    tr("Delete contents of the downloads cache folder, where archive files are staged during installation of libraries and boards platforms."),
+		Short:   i18n.Tr("Delete Boards/Library Manager download cache."),
+		Long:    i18n.Tr("Delete contents of the downloads cache folder, where archive files are staged during installation of libraries and boards platforms."),
 		Example: "  " + os.Args[0] + " cache clean",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
@@ -44,6 +45,6 @@ func runCleanCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer) {
 
 	_, err := srv.CleanDownloadCacheDirectory(ctx, &rpc.CleanDownloadCacheDirectoryRequest{})
 	if err != nil {
-		feedback.Fatal(tr("Error cleaning caches: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error cleaning caches: %v", err), feedback.ErrGeneric)
 	}
 }
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index c2333c1827b..91651b03c23 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -68,7 +68,6 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 		logFormat      string
 		jsonOutput     bool
 		outputFormat   string
-		configFile     string
 		additionalUrls []string
 	)
 
@@ -86,9 +85,9 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 
 	cmd := &cobra.Command{
 		Use:     "arduino-cli",
-		Short:   tr("Arduino CLI."),
-		Long:    tr("Arduino Command Line Interface (arduino-cli)."),
-		Example: fmt.Sprintf("  %s <%s> [%s...]", os.Args[0], tr("command"), tr("flags")),
+		Short:   i18n.Tr("Arduino CLI."),
+		Long:    i18n.Tr("Arduino Command Line Interface (arduino-cli)."),
+		Example: fmt.Sprintf("  %s <%s> [%s...]", os.Args[0], i18n.Tr("command"), i18n.Tr("flags")),
 		PersistentPreRun: func(cmd *cobra.Command, args []string) {
 			ctx := cmd.Context()
 
@@ -99,7 +98,7 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 			}
 			if outputFormat != "text" {
 				cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
-					feedback.Fatal(tr("Should show help message, but it is available only in TEXT mode."), feedback.ErrBadArgument)
+					feedback.Fatal(i18n.Tr("Should show help message, but it is available only in TEXT mode."), feedback.ErrBadArgument)
 				})
 			}
 
@@ -164,25 +163,27 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	cmd.AddCommand(version.NewCommand(srv))
 	cmd.AddCommand(feedback.NewCommand())
 
-	cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, tr("Print the logs on the standard output."))
+	cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, i18n.Tr("Print the logs on the standard output."))
 	cmd.Flag("verbose").Hidden = true
-	cmd.PersistentFlags().BoolVar(&verbose, "log", false, tr("Print the logs on the standard output."))
+	cmd.PersistentFlags().BoolVar(&verbose, "log", false, i18n.Tr("Print the logs on the standard output."))
 	validLogLevels := []string{"trace", "debug", "info", "warn", "error", "fatal", "panic"}
-	cmd.PersistentFlags().StringVar(&logLevel, "log-level", defaultLogLevel, tr("Messages with this level and above will be logged. Valid levels are: %s", strings.Join(validLogLevels, ", ")))
+	cmd.PersistentFlags().StringVar(&logLevel, "log-level", defaultLogLevel, i18n.Tr("Messages with this level and above will be logged. Valid levels are: %s", strings.Join(validLogLevels, ", ")))
 	cmd.RegisterFlagCompletionFunc("log-level", cobra.FixedCompletions(validLogLevels, cobra.ShellCompDirectiveDefault))
-	cmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, tr("Path to the file where logs will be written."))
+	cmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, i18n.Tr("Path to the file where logs will be written."))
 	validLogFormats := []string{"text", "json"}
-	cmd.PersistentFlags().StringVar(&logFormat, "log-format", defaultLogFormat, tr("The output format for the logs, can be: %s", strings.Join(validLogFormats, ", ")))
+	cmd.PersistentFlags().StringVar(&logFormat, "log-format", defaultLogFormat, i18n.Tr("The output format for the logs, can be: %s", strings.Join(validLogFormats, ", ")))
 	cmd.RegisterFlagCompletionFunc("log-format", cobra.FixedCompletions(validLogFormats, cobra.ShellCompDirectiveDefault))
 	validOutputFormats := []string{"text", "json", "jsonmini"}
-	cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", tr("The command output format, can be: %s", strings.Join(validOutputFormats, ", ")))
+	cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", i18n.Tr("The command output format, can be: %s", strings.Join(validOutputFormats, ", ")))
 	cmd.RegisterFlagCompletionFunc("format", cobra.FixedCompletions(validOutputFormats, cobra.ShellCompDirectiveDefault))
 	cmd.Flag("format").Hidden = true
-	cmd.PersistentFlags().BoolVar(&jsonOutput, "json", false, tr("Print the output in JSON format."))
-	cmd.PersistentFlags().StringVar(&configFile, "config-file", "", tr("The custom config file (if not specified the default will be used)."))
-	cmd.PersistentFlags().StringSliceVar(&additionalUrls, "additional-urls", defaultAdditionalURLs, tr("Comma-separated list of additional URLs for the Boards Manager."))
+	cmd.PersistentFlags().BoolVar(&jsonOutput, "json", false, i18n.Tr("Print the output in JSON format."))
+	cmd.PersistentFlags().StringSliceVar(&additionalUrls, "additional-urls", defaultAdditionalURLs, i18n.Tr("Comma-separated list of additional URLs for the Boards Manager."))
 	cmd.PersistentFlags().BoolVar(&noColor, "no-color", defaultOutputNoColor, "Disable colored output.")
 
+	// We are not using cobra to parse this flag, because we manually parse it in main.go.
+	// Just leaving it here so cobra will not complain about it.
+	cmd.PersistentFlags().String("config-file", "", i18n.Tr("The custom config file (if not specified the default will be used)."))
 	return cmd
 }
 
@@ -215,7 +216,7 @@ func preRun(verbose bool, outputFormat string, logLevel, logFile, logFormat stri
 	// use the output format to configure the Feedback
 	format, ok := feedback.ParseOutputFormat(outputFormat)
 	if !ok {
-		feedback.Fatal(tr("Invalid output format: %s", outputFormat), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid output format: %s", outputFormat), feedback.ErrBadArgument)
 	}
 	feedback.SetFormat(format)
 
@@ -245,7 +246,7 @@ func preRun(verbose bool, outputFormat string, logLevel, logFile, logFormat stri
 	if logFile != "" {
 		file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
 		if err != nil {
-			feedback.Fatal(tr("Unable to open file for logging: %s", logFile), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Unable to open file for logging: %s", logFile), feedback.ErrGeneric)
 		}
 
 		// we use a hook so we don't get color codes in the log file
@@ -258,7 +259,7 @@ func preRun(verbose bool, outputFormat string, logLevel, logFile, logFormat stri
 
 	// configure logging filter
 	if logrusLevel, found := toLogLevel(logLevel); !found {
-		feedback.Fatal(tr("Invalid logging level: %s", logLevel), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid logging level: %s", logLevel), feedback.ErrBadArgument)
 	} else {
 		logrus.SetLevel(logrusLevel)
 	}
diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go
index f04f01e8fc7..2a5348e981e 100644
--- a/internal/cli/compile/compile.go
+++ b/internal/cli/compile/compile.go
@@ -71,15 +71,14 @@ var (
 	library                []string // List of paths to libraries root folders. Can be used multiple times for different libraries
 	libraries              []string // List of custom libraries dir paths separated by commas. Or can be used multiple times for multiple libraries paths.
 	skipLibrariesDiscovery bool
-	tr                     = i18n.Tr
 )
 
 // NewCommand created a new `compile` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configuration) *cobra.Command {
 	compileCommand := &cobra.Command{
 		Use:   "compile",
-		Short: tr("Compiles Arduino sketches."),
-		Long:  tr("Compiles Arduino sketches."),
+		Short: i18n.Tr("Compiles Arduino sketches."),
+		Long:  i18n.Tr("Compiles Arduino sketches."),
 		Example: "" +
 			"  " + os.Args[0] + " compile -b arduino:avr:uno /home/user/Arduino/MySketch\n" +
 			"  " + os.Args[0] + ` compile -b arduino:avr:uno --build-property "build.extra_flags=\"-DMY_DEFINE=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n" +
@@ -93,47 +92,47 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configuration) *
 
 	fqbnArg.AddToCommand(compileCommand, srv)
 	profileArg.AddToCommand(compileCommand, srv)
-	compileCommand.Flags().BoolVar(&dumpProfile, "dump-profile", false, tr("Create and print a profile configuration from the build."))
+	compileCommand.Flags().BoolVar(&dumpProfile, "dump-profile", false, i18n.Tr("Create and print a profile configuration from the build."))
 	showPropertiesArg.AddToCommand(compileCommand)
-	compileCommand.Flags().BoolVar(&preprocess, "preprocess", false, tr("Print preprocessed code to stdout instead of compiling."))
-	compileCommand.Flags().StringVar(&buildCachePath, "build-cache-path", "", tr("Builds of 'core.a' are saved into this path to be cached and reused."))
-	compileCommand.Flags().StringVar(&exportDir, "output-dir", "", tr("Save build artifacts in this directory."))
+	compileCommand.Flags().BoolVar(&preprocess, "preprocess", false, i18n.Tr("Print preprocessed code to stdout instead of compiling."))
+	compileCommand.Flags().StringVar(&buildCachePath, "build-cache-path", "", i18n.Tr("Builds of 'core.a' are saved into this path to be cached and reused."))
+	compileCommand.Flags().StringVar(&exportDir, "output-dir", "", i18n.Tr("Save build artifacts in this directory."))
 	compileCommand.Flags().StringVar(&buildPath, "build-path", "",
-		tr("Path where to save compiled files. If omitted, a directory will be created in the default temporary path of your OS."))
+		i18n.Tr("Path where to save compiled files. If omitted, a directory will be created in the default temporary path of your OS."))
 	compileCommand.Flags().StringSliceVar(&buildProperties, "build-properties", []string{},
-		tr("List of custom build properties separated by commas. Or can be used multiple times for multiple properties."))
+		i18n.Tr("List of custom build properties separated by commas. Or can be used multiple times for multiple properties."))
 	compileCommand.Flags().StringArrayVar(&buildProperties, "build-property", []string{},
-		tr("Override a build property with a custom value. Can be used multiple times for multiple properties."))
+		i18n.Tr("Override a build property with a custom value. Can be used multiple times for multiple properties."))
 	compileCommand.Flags().StringVar(&keysKeychain, "keys-keychain", "",
-		tr("The path of the dir to search for the custom keys to sign and encrypt a binary. Used only by the platforms that support it."))
+		i18n.Tr("The path of the dir to search for the custom keys to sign and encrypt a binary. Used only by the platforms that support it."))
 	compileCommand.Flags().StringVar(&signKey, "sign-key", "",
-		tr("The name of the custom signing key to use to sign a binary during the compile process. Used only by the platforms that support it."))
+		i18n.Tr("The name of the custom signing key to use to sign a binary during the compile process. Used only by the platforms that support it."))
 	compileCommand.Flags().StringVar(&encryptKey, "encrypt-key", "",
-		tr("The name of the custom encryption key to use to encrypt a binary during the compile process. Used only by the platforms that support it."))
+		i18n.Tr("The name of the custom encryption key to use to encrypt a binary during the compile process. Used only by the platforms that support it."))
 	compileCommand.Flags().StringVar(&warnings, "warnings", "none",
-		tr(`Optional, can be: %s. Used to tell gcc which warning level to use (-W flag).`, "none, default, more, all"))
-	compileCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Optional, turns on verbose mode."))
-	compileCommand.Flags().BoolVar(&quiet, "quiet", false, tr("Optional, suppresses almost every output."))
-	compileCommand.Flags().BoolVarP(&uploadAfterCompile, "upload", "u", false, tr("Upload the binary after the compilation."))
+		i18n.Tr(`Optional, can be: %s. Used to tell gcc which warning level to use (-W flag).`, "none, default, more, all"))
+	compileCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, i18n.Tr("Optional, turns on verbose mode."))
+	compileCommand.Flags().BoolVar(&quiet, "quiet", false, i18n.Tr("Optional, suppresses almost every output."))
+	compileCommand.Flags().BoolVarP(&uploadAfterCompile, "upload", "u", false, i18n.Tr("Upload the binary after the compilation."))
 	portArgs.AddToCommand(compileCommand, srv)
-	compileCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload."))
+	compileCommand.Flags().BoolVarP(&verify, "verify", "t", false, i18n.Tr("Verify uploaded binary after the upload."))
 	compileCommand.Flags().StringSliceVar(&library, "library", []string{},
-		tr("Path to a single library’s root folder. Can be used multiple times or entries can be comma separated."))
+		i18n.Tr("Path to a single library’s root folder. Can be used multiple times or entries can be comma separated."))
 	compileCommand.Flags().StringSliceVar(&libraries, "libraries", []string{},
-		tr("Path to a collection of libraries. Can be used multiple times or entries can be comma separated."))
-	compileCommand.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, tr("Optional, optimize compile output for debugging, rather than for release."))
+		i18n.Tr("Path to a collection of libraries. Can be used multiple times or entries can be comma separated."))
+	compileCommand.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, i18n.Tr("Optional, optimize compile output for debugging, rather than for release."))
 	programmer.AddToCommand(compileCommand, srv)
-	compileCommand.Flags().BoolVar(&compilationDatabaseOnly, "only-compilation-database", false, tr("Just produce the compilation database, without actually compiling. All build commands are skipped except pre* hooks."))
-	compileCommand.Flags().BoolVar(&clean, "clean", false, tr("Optional, cleanup the build folder and do not use any cached build."))
+	compileCommand.Flags().BoolVar(&compilationDatabaseOnly, "only-compilation-database", false, i18n.Tr("Just produce the compilation database, without actually compiling. All build commands are skipped except pre* hooks."))
+	compileCommand.Flags().BoolVar(&clean, "clean", false, i18n.Tr("Optional, cleanup the build folder and do not use any cached build."))
 	compileCommand.Flags().BoolVarP(&exportBinaries, "export-binaries", "e", settings.GetSketch().GetAlwaysExportBinaries(),
-		tr("If set built binaries will be exported to the sketch folder."))
-	compileCommand.Flags().StringVar(&sourceOverrides, "source-override", "", tr("Optional. Path to a .json file that contains a set of replacements of the sketch source code."))
+		i18n.Tr("If set built binaries will be exported to the sketch folder."))
+	compileCommand.Flags().StringVar(&sourceOverrides, "source-override", "", i18n.Tr("Optional. Path to a .json file that contains a set of replacements of the sketch source code."))
 	compileCommand.Flag("source-override").Hidden = true
 	compileCommand.Flags().BoolVar(&skipLibrariesDiscovery, "skip-libraries-discovery", false, "Skip libraries discovery. This flag is provided only for use in language server and other, very specific, use cases. Do not use for normal compiles")
 	compileCommand.Flag("skip-libraries-discovery").Hidden = true
-	compileCommand.Flags().Int32VarP(&jobs, "jobs", "j", 0, tr("Max number of parallel compiles. If set to 0 the number of available CPUs cores will be used."))
+	compileCommand.Flags().Int32VarP(&jobs, "jobs", "j", 0, i18n.Tr("Max number of parallel compiles. If set to 0 the number of available CPUs cores will be used."))
 
-	compileCommand.Flags().MarkDeprecated("build-properties", tr("please use --build-property instead."))
+	compileCommand.Flags().MarkDeprecated("build-properties", i18n.Tr("please use --build-property instead."))
 
 	return compileCommand
 }
@@ -144,10 +143,10 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 
 	if profileArg.Get() != "" {
 		if len(libraries) > 0 {
-			feedback.Fatal(tr("You cannot use the %s flag while compiling with a profile.", "--libraries"), feedback.ErrBadArgument)
+			feedback.Fatal(i18n.Tr("You cannot use the %s flag while compiling with a profile.", "--libraries"), feedback.ErrBadArgument)
 		}
 		if len(library) > 0 {
-			feedback.Fatal(tr("You cannot use the %s flag while compiling with a profile.", "--library"), feedback.ErrBadArgument)
+			feedback.Fatal(i18n.Tr("You cannot use the %s flag while compiling with a profile.", "--library"), feedback.ErrBadArgument)
 		}
 	}
 
@@ -187,20 +186,20 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 	if sourceOverrides != "" {
 		data, err := paths.New(sourceOverrides).ReadFile()
 		if err != nil {
-			feedback.Fatal(tr("Error opening source code overrides data file: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error opening source code overrides data file: %v", err), feedback.ErrGeneric)
 		}
 		var o struct {
 			Overrides map[string]string `json:"overrides"`
 		}
 		if err := json.Unmarshal(data, &o); err != nil {
-			feedback.Fatal(tr("Error: invalid source code overrides data file: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error: invalid source code overrides data file: %v", err), feedback.ErrGeneric)
 		}
 		overrides = o.Overrides
 	}
 
 	showProperties, err := showPropertiesArg.Get()
 	if err != nil {
-		feedback.Fatal(tr("Error parsing --show-properties flag: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error parsing --show-properties flag: %v", err), feedback.ErrGeneric)
 	}
 
 	var stdOut, stdErr io.Writer
@@ -214,7 +213,7 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 	var libraryAbs []string
 	for _, libPath := range paths.NewPathList(library...) {
 		if libPath, err = libPath.Abs(); err != nil {
-			feedback.Fatal(tr("Error converting path to absolute: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error converting path to absolute: %v", err), feedback.ErrGeneric)
 		}
 		libraryAbs = append(libraryAbs, libPath.String())
 	}
@@ -258,12 +257,12 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 			Protocol: port.GetProtocol(),
 		})
 		if err != nil {
-			feedback.Fatal(tr("Error during Upload: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error during Upload: %v", err), feedback.ErrGeneric)
 		}
 
 		fields := map[string]string{}
 		if len(userFieldRes.GetUserFields()) > 0 {
-			feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.GetProtocol()))
+			feedback.Print(i18n.Tr("Uploading to specified board using %s protocol requires the following info:", port.GetProtocol()))
 			if f, err := arguments.AskForUserFields(userFieldRes.GetUserFields()); err != nil {
 				feedback.FatalError(err, feedback.ErrBadArgument)
 			} else {
@@ -300,7 +299,7 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 			if errors.Is(err, &cmderrors.MissingProgrammerError{}) {
 				errcode = feedback.ErrMissingProgrammer
 			}
-			feedback.Fatal(tr("Error during Upload: %v", err), errcode)
+			feedback.Fatal(i18n.Tr("Error during Upload: %v", err), errcode)
 		} else {
 			uploadRes = streamRes()
 		}
@@ -324,8 +323,8 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 		}
 		if hasVendoredLibs {
 			msg := "\n"
-			msg += tr("WARNING: The sketch is compiled using one or more custom libraries.") + "\n"
-			msg += tr("Currently, Build Profiles only support libraries available through Arduino Library Manager.")
+			msg += i18n.Tr("WARNING: The sketch is compiled using one or more custom libraries.") + "\n"
+			msg += i18n.Tr("Currently, Build Profiles only support libraries available through Arduino Library Manager.")
 			feedback.Warning(msg)
 		}
 
@@ -373,7 +372,7 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 	}
 
 	if compileError != nil {
-		res.Error = tr("Error during build: %v", compileError)
+		res.Error = i18n.Tr("Error during build: %v", compileError)
 
 		// Check the error type to give the user better feedback on how
 		// to resolve it
@@ -381,7 +380,7 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 		if errors.As(compileError, &platformErr) {
 			split := strings.Split(platformErr.Platform, ":")
 			if len(split) < 2 {
-				panic(tr("Platform ID is not correct"))
+				panic(i18n.Tr("Platform ID is not correct"))
 			}
 
 			if profileArg.String() == "" {
@@ -394,9 +393,9 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
 					res.Error += err.Error()
 				} else if len(platform.GetSearchOutput()) > 0 {
 					suggestion := fmt.Sprintf("`%s core install %s`", version.VersionInfo.Application, platformErr.Platform)
-					res.Error += tr("Try running %s", suggestion)
+					res.Error += i18n.Tr("Try running %s", suggestion)
 				} else {
-					res.Error += tr("Platform %s is not found in any known index\nMaybe you need to add a 3rd party URL?", platformErr.Platform)
+					res.Error += i18n.Tr("Platform %s is not found in any known index\nMaybe you need to add a 3rd party URL?", platformErr.Platform)
 				}
 			}
 		}
@@ -446,9 +445,9 @@ func (r *compileResult) String() string {
 	if build != nil && len(build.UsedLibraries) > 0 {
 		libraries := table.New()
 		libraries.SetHeader(
-			table.NewCell(tr("Used library"), titleColor),
-			table.NewCell(tr("Version"), titleColor),
-			table.NewCell(tr("Path"), pathColor))
+			table.NewCell(i18n.Tr("Used library"), titleColor),
+			table.NewCell(i18n.Tr("Version"), titleColor),
+			table.NewCell(i18n.Tr("Path"), pathColor))
 		for _, l := range build.UsedLibraries {
 			libraries.AddRow(
 				table.NewCell(l.Name, nameColor),
@@ -461,9 +460,9 @@ func (r *compileResult) String() string {
 		boardPlatform := build.BoardPlatform
 		platforms := table.New()
 		platforms.SetHeader(
-			table.NewCell(tr("Used platform"), titleColor),
-			table.NewCell(tr("Version"), titleColor),
-			table.NewCell(tr("Path"), pathColor))
+			table.NewCell(i18n.Tr("Used platform"), titleColor),
+			table.NewCell(i18n.Tr("Version"), titleColor),
+			table.NewCell(i18n.Tr("Path"), pathColor))
 		platforms.AddRow(
 			table.NewCell(boardPlatform.Id, nameColor),
 			boardPlatform.Version,
diff --git a/internal/cli/completion/completion.go b/internal/cli/completion/completion.go
index d4036d393aa..da3e19c397b 100644
--- a/internal/cli/completion/completion.go
+++ b/internal/cli/completion/completion.go
@@ -35,13 +35,13 @@ func NewCommand() *cobra.Command {
 		Use:       "completion [bash|zsh|fish|powershell] [--no-descriptions]",
 		ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
 		Args:      cobra.ExactArgs(1),
-		Short:     tr("Generates completion scripts"),
-		Long:      tr("Generates completion scripts for various shells"),
+		Short:     i18n.Tr("Generates completion scripts"),
+		Long:      i18n.Tr("Generates completion scripts for various shells"),
 		Example: "  " + os.Args[0] + " completion bash > completion.sh\n" +
 			"  " + "source completion.sh",
 		Run: runCompletionCommand,
 	}
-	completionCommand.Flags().BoolVar(&completionNoDesc, "no-descriptions", false, tr("Disable completion description for shells that support it"))
+	completionCommand.Flags().BoolVar(&completionNoDesc, "no-descriptions", false, i18n.Tr("Disable completion description for shells that support it"))
 
 	return completionCommand
 }
@@ -53,7 +53,7 @@ func runCompletionCommand(cmd *cobra.Command, args []string) {
 		feedback.Fatal(err.Error(), feedback.ErrGeneric)
 	}
 	if completionNoDesc && (args[0] == "powershell") {
-		feedback.Fatal(tr("Error: command description is not supported by %v", args[0]), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error: command description is not supported by %v", args[0]), feedback.ErrGeneric)
 	}
 	switch args[0] {
 	case "bash":
diff --git a/internal/cli/config/add.go b/internal/cli/config/add.go
index 059ecad07c1..d4950fd691b 100644
--- a/internal/cli/config/add.go
+++ b/internal/cli/config/add.go
@@ -22,6 +22,7 @@ import (
 	"slices"
 
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -30,8 +31,8 @@ import (
 func initAddCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	addCommand := &cobra.Command{
 		Use:   "add",
-		Short: tr("Adds one or more values to a setting."),
-		Long:  tr("Adds one or more values to a setting."),
+		Short: i18n.Tr("Adds one or more values to a setting."),
+		Long:  i18n.Tr("Adds one or more values to a setting."),
 		Example: "" +
 			"  " + os.Args[0] + " config add board_manager.additional_urls https://example.com/package_example_index.json\n" +
 			"  " + os.Args[0] + " config add board_manager.additional_urls https://example.com/package_example_index.json https://another-url.com/package_another_index.json\n",
@@ -53,15 +54,15 @@ func runAddCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
 	key := args[0]
 
 	if !slices.Contains(getAllArraySettingsKeys(ctx, srv), key) {
-		msg := tr("The key '%[1]v' is not a list of items, can't add to it.\nMaybe use '%[2]s'?", key, "config set")
+		msg := i18n.Tr("The key '%[1]v' is not a list of items, can't add to it.\nMaybe use '%[2]s'?", key, "config set")
 		feedback.Fatal(msg, feedback.ErrGeneric)
 	}
 
 	var currentValues []string
 	if resp, err := srv.SettingsGetValue(ctx, &rpc.SettingsGetValueRequest{Key: key}); err != nil {
-		feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	} else if err := json.Unmarshal([]byte(resp.GetEncodedValue()), &currentValues); err != nil {
-		feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	}
 
 	for _, arg := range args[1:] {
@@ -71,9 +72,9 @@ func runAddCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
 	}
 
 	if newValuesJSON, err := json.Marshal(currentValues); err != nil {
-		feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: string(newValuesJSON)}); err != nil {
-		feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	}
 
 	saveConfiguration(ctx, srv)
diff --git a/internal/cli/config/config.go b/internal/cli/config/config.go
index 2662befe322..d05f43ff77c 100644
--- a/internal/cli/config/config.go
+++ b/internal/cli/config/config.go
@@ -28,13 +28,11 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `config` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configuration) *cobra.Command {
 	configCommand := &cobra.Command{
 		Use:     "config",
-		Short:   tr("Arduino configuration commands."),
+		Short:   i18n.Tr("Arduino configuration commands."),
 		Example: "  " + os.Args[0] + " config init",
 	}
 
@@ -83,13 +81,13 @@ func SetConfigFile(ctx context.Context, configFile string) context.Context {
 func saveConfiguration(ctx context.Context, srv rpc.ArduinoCoreServiceServer) {
 	var outConfig []byte
 	if res, err := srv.ConfigurationSave(ctx, &rpc.ConfigurationSaveRequest{SettingsFormat: "yaml"}); err != nil {
-		feedback.Fatal(tr("Error writing to file: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error writing to file: %v", err), feedback.ErrGeneric)
 	} else {
 		outConfig = []byte(res.GetEncodedSettings())
 	}
 
 	configFile := GetConfigFile(ctx)
 	if err := paths.New(configFile).WriteFile(outConfig); err != nil {
-		feedback.Fatal(tr("Error writing to file: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error writing to file: %v", err), feedback.ErrGeneric)
 	}
 }
diff --git a/internal/cli/config/delete.go b/internal/cli/config/delete.go
index 7ba5437cda2..e0ff13a1455 100644
--- a/internal/cli/config/delete.go
+++ b/internal/cli/config/delete.go
@@ -20,6 +20,7 @@ import (
 	"os"
 
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -28,8 +29,8 @@ import (
 func initDeleteCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	deleteCommand := &cobra.Command{
 		Use:   "delete",
-		Short: tr("Deletes a settings key and all its sub keys."),
-		Long:  tr("Deletes a settings key and all its sub keys."),
+		Short: i18n.Tr("Deletes a settings key and all its sub keys."),
+		Long:  i18n.Tr("Deletes a settings key and all its sub keys."),
 		Example: "" +
 			"  " + os.Args[0] + " config delete board_manager\n" +
 			"  " + os.Args[0] + " config delete board_manager.additional_urls",
@@ -51,7 +52,7 @@ func runDeleteCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 
 	key := args[0]
 	if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: ""}); err != nil {
-		feedback.Fatal(tr("Cannot delete the key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot delete the key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	}
 
 	saveConfiguration(ctx, srv)
diff --git a/internal/cli/config/dump.go b/internal/cli/config/dump.go
index 5212ec9d1fa..6b78e83e83d 100644
--- a/internal/cli/config/dump.go
+++ b/internal/cli/config/dump.go
@@ -19,6 +19,7 @@ import (
 	"os"
 
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -27,8 +28,8 @@ import (
 func initDumpCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var dumpCommand = &cobra.Command{
 		Use:     "dump",
-		Short:   tr("Prints the current configuration"),
-		Long:    tr("Prints the current configuration."),
+		Short:   i18n.Tr("Prints the current configuration"),
+		Long:    i18n.Tr("Prints the current configuration."),
 		Example: "  " + os.Args[0] + " config dump",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
diff --git a/internal/cli/config/get.go b/internal/cli/config/get.go
index 3dfb5345c20..8ac4451ee9f 100644
--- a/internal/cli/config/get.go
+++ b/internal/cli/config/get.go
@@ -22,6 +22,7 @@ import (
 	"os"
 
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,8 +32,8 @@ import (
 func initGetCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	getCommand := &cobra.Command{
 		Use:   "get",
-		Short: tr("Gets a settings key value."),
-		Long:  tr("Gets a settings key value."),
+		Short: i18n.Tr("Gets a settings key value."),
+		Long:  i18n.Tr("Gets a settings key value."),
 		Example: "" +
 			"  " + os.Args[0] + " config get logging\n" +
 			"  " + os.Args[0] + " config get daemon.port\n" +
@@ -55,7 +56,7 @@ func runGetCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
 	for _, toGet := range args {
 		resp, err := srv.SettingsGetValue(ctx, &rpc.SettingsGetValueRequest{Key: toGet})
 		if err != nil {
-			feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", toGet, err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Cannot get the configuration key %[1]s: %[2]v", toGet, err), feedback.ErrGeneric)
 		}
 		var result getResult
 		if err := json.Unmarshal([]byte(resp.GetEncodedValue()), &result.resp); err != nil {
@@ -81,7 +82,7 @@ func (gr getResult) String() string {
 	gs, err := yaml.Marshal(gr.resp)
 	if err != nil {
 		// Should never happen
-		panic(tr("unable to marshal config to YAML: %v", err))
+		panic(i18n.Tr("unable to marshal config to YAML: %v", err))
 	}
 	return string(gs)
 }
diff --git a/internal/cli/config/init.go b/internal/cli/config/init.go
index 4e297fda7c5..85491492d21 100644
--- a/internal/cli/config/init.go
+++ b/internal/cli/config/init.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/commands"
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -41,10 +42,10 @@ const defaultFileName = "arduino-cli.yaml"
 func initInitCommand() *cobra.Command {
 	initCommand := &cobra.Command{
 		Use:   "init",
-		Short: tr("Writes current configuration to a configuration file."),
-		Long:  tr("Creates or updates the configuration file in the data directory or custom directory with the current configuration settings."),
+		Short: i18n.Tr("Writes current configuration to a configuration file."),
+		Long:  i18n.Tr("Creates or updates the configuration file in the data directory or custom directory with the current configuration settings."),
 		Example: "" +
-			"  # " + tr("Writes current configuration to the configuration file in the data directory.") + "\n" +
+			"  # " + i18n.Tr("Writes current configuration to the configuration file in the data directory.") + "\n" +
 			"  " + os.Args[0] + " config init\n" +
 			"  " + os.Args[0] + " config init --dest-dir /home/user/MyDirectory\n" +
 			"  " + os.Args[0] + " config init --dest-file /home/user/MyDirectory/my_settings.yaml",
@@ -56,9 +57,9 @@ func initInitCommand() *cobra.Command {
 			runInitCommand(cmd.Context(), cmd)
 		},
 	}
-	initCommand.Flags().StringVar(&destDir, "dest-dir", "", tr("Sets where to save the configuration file."))
-	initCommand.Flags().StringVar(&destFile, "dest-file", "", tr("Sets where to save the configuration file."))
-	initCommand.Flags().BoolVar(&overwrite, "overwrite", false, tr("Overwrite existing config file."))
+	initCommand.Flags().StringVar(&destDir, "dest-dir", "", i18n.Tr("Sets where to save the configuration file."))
+	initCommand.Flags().StringVar(&destFile, "dest-file", "", i18n.Tr("Sets where to save the configuration file."))
+	initCommand.Flags().BoolVar(&overwrite, "overwrite", false, i18n.Tr("Overwrite existing config file."))
 	return initCommand
 }
 
@@ -73,14 +74,14 @@ func runInitCommand(ctx context.Context, cmd *cobra.Command) {
 	case destFile != "":
 		configFileAbsPath, err = paths.New(destFile).Abs()
 		if err != nil {
-			feedback.Fatal(tr("Cannot find absolute path: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Cannot find absolute path: %v", err), feedback.ErrGeneric)
 		}
 		configFileDir = configFileAbsPath.Parent()
 
 	case destDir != "":
 		configFileDir, err = paths.New(destDir).Abs()
 		if err != nil {
-			feedback.Fatal(tr("Cannot find absolute path: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Cannot find absolute path: %v", err), feedback.ErrGeneric)
 		}
 		configFileAbsPath = configFileDir.Join(defaultFileName)
 
@@ -90,37 +91,37 @@ func runInitCommand(ctx context.Context, cmd *cobra.Command) {
 	}
 
 	if !overwrite && configFileAbsPath.Exist() {
-		feedback.Fatal(tr("Config file already exists, use --overwrite to discard the existing one."), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Config file already exists, use --overwrite to discard the existing one."), feedback.ErrGeneric)
 	}
 
 	logrus.Infof("Writing config file to: %s", configFileDir)
 
 	if err := configFileDir.MkdirAll(); err != nil {
-		feedback.Fatal(tr("Cannot create config file directory: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot create config file directory: %v", err), feedback.ErrGeneric)
 	}
 
 	tmpSrv := commands.NewArduinoCoreServer()
 
 	if _, err := tmpSrv.ConfigurationOpen(ctx, &rpc.ConfigurationOpenRequest{SettingsFormat: "yaml", EncodedSettings: ""}); err != nil {
-		feedback.Fatal(tr("Error creating configuration: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error creating configuration: %v", err), feedback.ErrGeneric)
 	}
 
 	// Ensure to always output an empty array for additional urls
 	if _, err := tmpSrv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{
 		Key: "board_manager.additional_urls", EncodedValue: "[]",
 	}); err != nil {
-		feedback.Fatal(tr("Error creating configuration: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error creating configuration: %v", err), feedback.ErrGeneric)
 	}
 
 	ApplyGlobalFlagsToConfiguration(ctx, cmd, tmpSrv)
 
 	resp, err := tmpSrv.ConfigurationSave(ctx, &rpc.ConfigurationSaveRequest{SettingsFormat: "yaml"})
 	if err != nil {
-		feedback.Fatal(tr("Error creating configuration: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error creating configuration: %v", err), feedback.ErrGeneric)
 	}
 
 	if err := configFileAbsPath.WriteFile([]byte(resp.GetEncodedSettings())); err != nil {
-		feedback.Fatal(tr("Cannot create config file: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot create config file: %v", err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(initResult{ConfigFileAbsPath: configFileAbsPath})
@@ -130,11 +131,11 @@ func runInitCommand(ctx context.Context, cmd *cobra.Command) {
 func ApplyGlobalFlagsToConfiguration(ctx context.Context, cmd *cobra.Command, srv rpc.ArduinoCoreServiceServer) {
 	set := func(k string, v any) {
 		if jsonValue, err := json.Marshal(v); err != nil {
-			feedback.Fatal(tr("Error creating configuration: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error creating configuration: %v", err), feedback.ErrGeneric)
 		} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{
 			Key: k, EncodedValue: string(jsonValue),
 		}); err != nil {
-			feedback.Fatal(tr("Error creating configuration: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error creating configuration: %v", err), feedback.ErrGeneric)
 		}
 
 	}
@@ -156,7 +157,7 @@ func ApplyGlobalFlagsToConfiguration(ctx context.Context, cmd *cobra.Command, sr
 		for _, url := range urls {
 			if strings.Contains(url, ",") {
 				feedback.Fatal(
-					tr("Urls cannot contain commas. Separate multiple urls exported as env var with a space:\n%s", url),
+					i18n.Tr("Urls cannot contain commas. Separate multiple urls exported as env var with a space:\n%s", url),
 					feedback.ErrBadArgument)
 			}
 		}
@@ -175,7 +176,7 @@ func (dr initResult) Data() interface{} {
 }
 
 func (dr initResult) String() string {
-	msg := tr("Config file written to: %s", dr.ConfigFileAbsPath.String())
+	msg := i18n.Tr("Config file written to: %s", dr.ConfigFileAbsPath.String())
 	logrus.Info(msg)
 	return msg
 }
diff --git a/internal/cli/config/remove.go b/internal/cli/config/remove.go
index 4114a146a45..45592e5a058 100644
--- a/internal/cli/config/remove.go
+++ b/internal/cli/config/remove.go
@@ -22,6 +22,7 @@ import (
 	"slices"
 
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -30,8 +31,8 @@ import (
 func initRemoveCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	removeCommand := &cobra.Command{
 		Use:   "remove",
-		Short: tr("Removes one or more values from a setting."),
-		Long:  tr("Removes one or more values from a setting."),
+		Short: i18n.Tr("Removes one or more values from a setting."),
+		Long:  i18n.Tr("Removes one or more values from a setting."),
 		Example: "" +
 			"  " + os.Args[0] + " config remove board_manager.additional_urls https://example.com/package_example_index.json\n" +
 			"  " + os.Args[0] + " config remove board_manager.additional_urls https://example.com/package_example_index.json https://another-url.com/package_another_index.json\n",
@@ -53,15 +54,15 @@ func runRemoveCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 	key := args[0]
 
 	if !slices.Contains(getAllArraySettingsKeys(ctx, srv), key) {
-		msg := tr("The key '%[1]v' is not a list of items, can't remove from it.\nMaybe use '%[2]s'?", key, "config delete")
+		msg := i18n.Tr("The key '%[1]v' is not a list of items, can't remove from it.\nMaybe use '%[2]s'?", key, "config delete")
 		feedback.Fatal(msg, feedback.ErrGeneric)
 	}
 
 	var currentValues []string
 	if resp, err := srv.SettingsGetValue(ctx, &rpc.SettingsGetValueRequest{Key: key}); err != nil {
-		feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	} else if err := json.Unmarshal([]byte(resp.GetEncodedValue()), &currentValues); err != nil {
-		feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	}
 
 	for _, arg := range args[1:] {
@@ -69,9 +70,9 @@ func runRemoveCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 	}
 
 	if newValuesJSON, err := json.Marshal(currentValues); err != nil {
-		feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: string(newValuesJSON)}); err != nil {
-		feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
 	}
 
 	saveConfiguration(ctx, srv)
diff --git a/internal/cli/config/set.go b/internal/cli/config/set.go
index a722f3f176b..34c1d3168e2 100644
--- a/internal/cli/config/set.go
+++ b/internal/cli/config/set.go
@@ -22,6 +22,7 @@ import (
 
 	f "github.com/arduino/arduino-cli/internal/algorithms"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -30,8 +31,8 @@ import (
 func initSetCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	setCommand := &cobra.Command{
 		Use:   "set",
-		Short: tr("Sets a setting value."),
-		Long:  tr("Sets a setting value."),
+		Short: i18n.Tr("Sets a setting value."),
+		Long:  i18n.Tr("Sets a setting value."),
 		Example: "" +
 			"  " + os.Args[0] + " config set logging.level trace\n" +
 			"  " + os.Args[0] + " config set logging.file my-log.txt\n" +
@@ -63,14 +64,14 @@ func runSetCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
 		// Uniq Array
 		jsonValues, err := json.Marshal(f.Uniq(args[1:]))
 		if err != nil {
-			feedback.Fatal(tr("Error setting value: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error setting value: %v", err), feedback.ErrGeneric)
 		}
 		req.EncodedValue = string(jsonValues)
 		req.ValueFormat = "json"
 	}
 
 	if _, err := srv.SettingsSetValue(ctx, req); err != nil {
-		feedback.Fatal(tr("Error setting value: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error setting value: %v", err), feedback.ErrGeneric)
 	}
 
 	saveConfiguration(ctx, srv)
diff --git a/internal/cli/configuration/configuration.go b/internal/cli/configuration/configuration.go
index 5176acc9a28..8ceef039af6 100644
--- a/internal/cli/configuration/configuration.go
+++ b/internal/cli/configuration/configuration.go
@@ -26,8 +26,6 @@ import (
 	"github.com/arduino/go-win32-utils"
 )
 
-var tr = i18n.Tr
-
 // Settings contains the configuration of the Arduino CLI core service
 type Settings struct {
 	*configmap.Map
@@ -48,7 +46,7 @@ func NewSettings() *Settings {
 func getDefaultArduinoDataDir() string {
 	userHomeDir, err := os.UserHomeDir()
 	if err != nil {
-		feedback.Warning(tr("Unable to get user home dir: %v", err))
+		feedback.Warning(i18n.Tr("Unable to get user home dir: %v", err))
 		return "."
 	}
 
@@ -60,7 +58,7 @@ func getDefaultArduinoDataDir() string {
 	case "windows":
 		localAppDataPath, err := win32.GetLocalAppDataFolder()
 		if err != nil {
-			feedback.Warning(tr("Unable to get Local App Data Folder: %v", err))
+			feedback.Warning(i18n.Tr("Unable to get Local App Data Folder: %v", err))
 			return "."
 		}
 		return filepath.Join(localAppDataPath, "Arduino15")
@@ -73,7 +71,7 @@ func getDefaultArduinoDataDir() string {
 func getDefaultUserDir() string {
 	userHomeDir, err := os.UserHomeDir()
 	if err != nil {
-		feedback.Warning(tr("Unable to get user home dir: %v", err))
+		feedback.Warning(i18n.Tr("Unable to get user home dir: %v", err))
 		return "."
 	}
 
@@ -85,7 +83,7 @@ func getDefaultUserDir() string {
 	case "windows":
 		documentsPath, err := win32.GetDocumentsFolder()
 		if err != nil {
-			feedback.Warning(tr("Unable to get Documents Folder: %v", err))
+			feedback.Warning(i18n.Tr("Unable to get Documents Folder: %v", err))
 			return "."
 		}
 		return filepath.Join(documentsPath, "Arduino")
diff --git a/internal/cli/configuration/network.go b/internal/cli/configuration/network.go
index 7fac7ee6890..9ffcdf8bd25 100644
--- a/internal/cli/configuration/network.go
+++ b/internal/cli/configuration/network.go
@@ -16,6 +16,7 @@
 package configuration
 
 import (
+	"errors"
 	"fmt"
 	"net/http"
 	"net/url"
@@ -23,6 +24,7 @@ import (
 	"runtime"
 
 	"github.com/arduino/arduino-cli/commands/cmderrors"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/arduino/arduino-cli/version"
 	"go.bug.st/downloader/v2"
 )
@@ -61,7 +63,7 @@ func (settings *Settings) NetworkProxy() (*url.URL, error) {
 	if proxyConfig, ok, _ := settings.GetStringOk("network.proxy"); !ok {
 		return nil, nil
 	} else if proxy, err := url.Parse(proxyConfig); err != nil {
-		return nil, fmt.Errorf(tr("Invalid network.proxy '%[1]s': %[2]s"), proxyConfig, err)
+		return nil, errors.New(i18n.Tr("Invalid network.proxy '%[1]s': %[2]s", proxyConfig, err))
 	} else {
 		return proxy, nil
 	}
@@ -98,7 +100,7 @@ func (settings *Settings) DownloaderConfig() (downloader.Config, error) {
 	httpClient, err := settings.NewHttpClient()
 	if err != nil {
 		return downloader.Config{}, &cmderrors.InvalidArgumentError{
-			Message: tr("Could not connect via HTTP"),
+			Message: i18n.Tr("Could not connect via HTTP"),
 			Cause:   err}
 	}
 	return downloader.Config{
diff --git a/internal/cli/core/core.go b/internal/cli/core/core.go
index ac337df6c9e..c966db14e93 100644
--- a/internal/cli/core/core.go
+++ b/internal/cli/core/core.go
@@ -23,14 +23,12 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `core` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	coreCommand := &cobra.Command{
 		Use:     "core",
-		Short:   tr("Arduino core operations."),
-		Long:    tr("Arduino core operations."),
+		Short:   i18n.Tr("Arduino core operations."),
+		Long:    i18n.Tr("Arduino core operations."),
 		Example: "  " + os.Args[0] + " core update-index",
 	}
 
diff --git a/internal/cli/core/download.go b/internal/cli/core/download.go
index fb5fe3f3818..c4e7ee8732c 100644
--- a/internal/cli/core/download.go
+++ b/internal/cli/core/download.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,12 +32,12 @@ import (
 
 func initDownloadCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	downloadCommand := &cobra.Command{
-		Use:   fmt.Sprintf("download [%s:%s[@%s]]...", tr("PACKAGER"), tr("ARCH"), tr("VERSION")),
-		Short: tr("Downloads one or more cores and corresponding tool dependencies."),
-		Long:  tr("Downloads one or more cores and corresponding tool dependencies."),
+		Use:   fmt.Sprintf("download [%s:%s[@%s]]...", i18n.Tr("PACKAGER"), i18n.Tr("ARCH"), i18n.Tr("VERSION")),
+		Short: i18n.Tr("Downloads one or more cores and corresponding tool dependencies."),
+		Long:  i18n.Tr("Downloads one or more cores and corresponding tool dependencies."),
 		Example: "" +
-			"  " + os.Args[0] + " core download arduino:samd       # " + tr("download the latest version of Arduino SAMD core.") + "\n" +
-			"  " + os.Args[0] + " core download arduino:samd@1.6.9 # " + tr("download a specific version (in this case 1.6.9)."),
+			"  " + os.Args[0] + " core download arduino:samd       # " + i18n.Tr("download the latest version of Arduino SAMD core.") + "\n" +
+			"  " + os.Args[0] + " core download arduino:samd@1.6.9 # " + i18n.Tr("download a specific version (in this case 1.6.9)."),
 		Args: cobra.MinimumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
 			runDownloadCommand(cmd.Context(), srv, args)
@@ -55,7 +56,7 @@ func runDownloadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, a
 
 	platformsRefs, err := arguments.ParseReferences(ctx, srv, args)
 	if err != nil {
-		feedback.Fatal(tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
 	}
 
 	for i, platformRef := range platformsRefs {
@@ -67,7 +68,7 @@ func runDownloadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, a
 		}
 		stream := commands.PlatformDownloadStreamResponseToCallbackFunction(ctx, feedback.ProgressBar())
 		if err := srv.PlatformDownload(platformDownloadreq, stream); err != nil {
-			feedback.Fatal(tr("Error downloading %[1]s: %[2]v", args[i], err), feedback.ErrNetwork)
+			feedback.Fatal(i18n.Tr("Error downloading %[1]s: %[2]v", args[i], err), feedback.ErrNetwork)
 		}
 	}
 }
diff --git a/internal/cli/core/install.go b/internal/cli/core/install.go
index 988602fc2ac..8a0e7284d35 100644
--- a/internal/cli/core/install.go
+++ b/internal/cli/core/install.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -33,12 +34,12 @@ func initInstallCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var noOverwrite bool
 	var scriptFlags arguments.PrePostScriptsFlags
 	installCommand := &cobra.Command{
-		Use:   fmt.Sprintf("install %s:%s[@%s]...", tr("PACKAGER"), tr("ARCH"), tr("VERSION")),
-		Short: tr("Installs one or more cores and corresponding tool dependencies."),
-		Long:  tr("Installs one or more cores and corresponding tool dependencies."),
-		Example: "  # " + tr("download the latest version of Arduino SAMD core.") + "\n" +
+		Use:   fmt.Sprintf("install %s:%s[@%s]...", i18n.Tr("PACKAGER"), i18n.Tr("ARCH"), i18n.Tr("VERSION")),
+		Short: i18n.Tr("Installs one or more cores and corresponding tool dependencies."),
+		Long:  i18n.Tr("Installs one or more cores and corresponding tool dependencies."),
+		Example: "  # " + i18n.Tr("download the latest version of Arduino SAMD core.") + "\n" +
 			"  " + os.Args[0] + " core install arduino:samd\n\n" +
-			"  # " + tr("download a specific version (in this case 1.6.9).") + "\n" +
+			"  # " + i18n.Tr("download a specific version (in this case 1.6.9).") + "\n" +
 			"  " + os.Args[0] + " core install arduino:samd@1.6.9",
 		Args: cobra.MinimumNArgs(1),
 		PreRun: func(cmd *cobra.Command, args []string) {
@@ -52,7 +53,7 @@ func initInstallCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 		},
 	}
 	scriptFlags.AddToCommand(installCommand)
-	installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, tr("Do not overwrite already installed platforms."))
+	installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, i18n.Tr("Do not overwrite already installed platforms."))
 	return installCommand
 }
 
@@ -62,7 +63,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 
 	platformsRefs, err := arguments.ParseReferences(ctx, srv, args)
 	if err != nil {
-		feedback.Fatal(tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
 	}
 
 	for _, platformRef := range platformsRefs {
@@ -77,7 +78,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 		}
 		stream := commands.PlatformInstallStreamResponseToCallbackFunction(ctx, feedback.ProgressBar(), feedback.TaskProgress())
 		if err := srv.PlatformInstall(platformInstallRequest, stream); err != nil {
-			feedback.Fatal(tr("Error during install: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error during install: %v", err), feedback.ErrGeneric)
 		}
 	}
 }
diff --git a/internal/cli/core/list.go b/internal/cli/core/list.go
index 3c2dd954818..24bae8a82ab 100644
--- a/internal/cli/core/list.go
+++ b/internal/cli/core/list.go
@@ -23,6 +23,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -33,16 +34,16 @@ func initListCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var all bool
 	listCommand := &cobra.Command{
 		Use:     "list",
-		Short:   tr("Shows the list of installed platforms."),
-		Long:    tr("Shows the list of installed platforms."),
+		Short:   i18n.Tr("Shows the list of installed platforms."),
+		Long:    i18n.Tr("Shows the list of installed platforms."),
 		Example: "  " + os.Args[0] + " core list",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
 			runListCommand(cmd.Context(), srv, all, updatableOnly)
 		},
 	}
-	listCommand.Flags().BoolVar(&updatableOnly, "updatable", false, tr("List updatable platforms."))
-	listCommand.Flags().BoolVar(&all, "all", false, tr("If set return all installable and installed cores, including manually installed."))
+	listCommand.Flags().BoolVar(&updatableOnly, "updatable", false, i18n.Tr("List updatable platforms."))
+	listCommand.Flags().BoolVar(&all, "all", false, i18n.Tr("If set return all installable and installed cores, including manually installed."))
 	return listCommand
 }
 
@@ -65,7 +66,7 @@ func GetList(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rpc.In
 		ManuallyInstalled: true,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error listing platforms: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error listing platforms: %v", err), feedback.ErrGeneric)
 	}
 
 	// If both `all` and `updatableOnly` are set, `all` takes precedence.
@@ -108,12 +109,12 @@ func (ir coreListResult) Data() interface{} {
 func (ir coreListResult) String() string {
 	if len(ir.Platforms) == 0 {
 		if ir.updatableOnly {
-			return tr("All platforms are up to date.")
+			return i18n.Tr("All platforms are up to date.")
 		}
-		return tr("No platforms installed.")
+		return i18n.Tr("No platforms installed.")
 	}
 	t := table.New()
-	t.SetHeader(tr("ID"), tr("Installed"), tr("Latest"), tr("Name"))
+	t.SetHeader(i18n.Tr("ID"), i18n.Tr("Installed"), i18n.Tr("Latest"), i18n.Tr("Name"))
 	for _, platform := range ir.Platforms {
 		latestVersion := platform.LatestVersion.String()
 		if latestVersion == "" {
diff --git a/internal/cli/core/search.go b/internal/cli/core/search.go
index 8a58cbf5a57..590fce9e62d 100644
--- a/internal/cli/core/search.go
+++ b/internal/cli/core/search.go
@@ -27,6 +27,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -35,16 +36,16 @@ import (
 func initSearchCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var allVersions bool
 	searchCommand := &cobra.Command{
-		Use:     fmt.Sprintf("search <%s...>", tr("keywords")),
-		Short:   tr("Search for a core in Boards Manager."),
-		Long:    tr("Search for a core in Boards Manager using the specified keywords."),
+		Use:     fmt.Sprintf("search <%s...>", i18n.Tr("keywords")),
+		Short:   i18n.Tr("Search for a core in Boards Manager."),
+		Long:    i18n.Tr("Search for a core in Boards Manager using the specified keywords."),
 		Example: "  " + os.Args[0] + " core search MKRZero -a -v",
 		Args:    cobra.ArbitraryArgs,
 		Run: func(cmd *cobra.Command, args []string) {
 			runSearchCommand(cmd.Context(), srv, args, allVersions)
 		},
 	}
-	searchCommand.Flags().BoolVarP(&allVersions, "all", "a", false, tr("Show all available core versions."))
+	searchCommand.Flags().BoolVarP(&allVersions, "all", "a", false, i18n.Tr("Show all available core versions."))
 
 	return searchCommand
 }
@@ -78,7 +79,7 @@ func runSearchCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 		SearchArgs: arguments,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error searching for platforms: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error searching for platforms: %v", err), feedback.ErrGeneric)
 	}
 
 	coreslist := resp.GetSearchOutput()
@@ -109,11 +110,11 @@ func (sr searchResults) Data() interface{} {
 
 func (sr searchResults) String() string {
 	if len(sr.Platforms) == 0 {
-		return tr("No platforms matching your search.")
+		return i18n.Tr("No platforms matching your search.")
 	}
 
 	t := table.New()
-	t.SetHeader(tr("ID"), tr("Version"), tr("Name"))
+	t.SetHeader(i18n.Tr("ID"), i18n.Tr("Version"), i18n.Tr("Name"))
 
 	addRow := func(platform *result.PlatformSummary, release *result.PlatformRelease) {
 		if release == nil {
diff --git a/internal/cli/core/uninstall.go b/internal/cli/core/uninstall.go
index a5df772935c..b939c5789e6 100644
--- a/internal/cli/core/uninstall.go
+++ b/internal/cli/core/uninstall.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -32,9 +33,9 @@ import (
 func initUninstallCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var preUninstallFlags arguments.PrePostScriptsFlags
 	uninstallCommand := &cobra.Command{
-		Use:     fmt.Sprintf("uninstall %s:%s ...", tr("PACKAGER"), tr("ARCH")),
-		Short:   tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
-		Long:    tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
+		Use:     fmt.Sprintf("uninstall %s:%s ...", i18n.Tr("PACKAGER"), i18n.Tr("ARCH")),
+		Short:   i18n.Tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
+		Long:    i18n.Tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
 		Example: "  " + os.Args[0] + " core uninstall arduino:samd\n",
 		Args:    cobra.MinimumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
@@ -54,12 +55,12 @@ func runUninstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer,
 
 	platformsRefs, err := arguments.ParseReferences(ctx, srv, args)
 	if err != nil {
-		feedback.Fatal(tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
 	}
 
 	for _, platformRef := range platformsRefs {
 		if platformRef.Version != "" {
-			feedback.Fatal(tr("Invalid parameter %s: version not allowed", platformRef), feedback.ErrBadArgument)
+			feedback.Fatal(i18n.Tr("Invalid parameter %s: version not allowed", platformRef), feedback.ErrBadArgument)
 		}
 	}
 	for _, platformRef := range platformsRefs {
@@ -71,7 +72,7 @@ func runUninstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer,
 		}
 		stream := commands.PlatformUninstallStreamResponseToCallbackFunction(ctx, feedback.NewTaskProgressCB())
 		if err := srv.PlatformUninstall(req, stream); err != nil {
-			feedback.Fatal(tr("Error during uninstall: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error during uninstall: %v", err), feedback.ErrGeneric)
 		}
 	}
 }
diff --git a/internal/cli/core/update_index.go b/internal/cli/core/update_index.go
index c7f0129291b..d18e006defb 100644
--- a/internal/cli/core/update_index.go
+++ b/internal/cli/core/update_index.go
@@ -23,6 +23,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,8 +32,8 @@ import (
 func initUpdateIndexCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	updateIndexCommand := &cobra.Command{
 		Use:     "update-index",
-		Short:   tr("Updates the index of cores."),
-		Long:    tr("Updates the index of cores to the latest version."),
+		Short:   i18n.Tr("Updates the index of cores."),
+		Long:    i18n.Tr("Updates the index of cores to the latest version."),
 		Example: "  " + os.Args[0] + " core update-index",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
diff --git a/internal/cli/core/upgrade.go b/internal/cli/core/upgrade.go
index ccbae460315..ee65e47e806 100644
--- a/internal/cli/core/upgrade.go
+++ b/internal/cli/core/upgrade.go
@@ -26,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -34,13 +35,13 @@ import (
 func initUpgradeCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var postInstallFlags arguments.PrePostScriptsFlags
 	upgradeCommand := &cobra.Command{
-		Use:   fmt.Sprintf("upgrade [%s:%s] ...", tr("PACKAGER"), tr("ARCH")),
-		Short: tr("Upgrades one or all installed platforms to the latest version."),
-		Long:  tr("Upgrades one or all installed platforms to the latest version."),
+		Use:   fmt.Sprintf("upgrade [%s:%s] ...", i18n.Tr("PACKAGER"), i18n.Tr("ARCH")),
+		Short: i18n.Tr("Upgrades one or all installed platforms to the latest version."),
+		Long:  i18n.Tr("Upgrades one or all installed platforms to the latest version."),
 		Example: "" +
-			"  # " + tr("upgrade everything to the latest version") + "\n" +
+			"  # " + i18n.Tr("upgrade everything to the latest version") + "\n" +
 			"  " + os.Args[0] + " core upgrade\n\n" +
-			"  # " + tr("upgrade arduino:samd to the latest version") + "\n" +
+			"  # " + i18n.Tr("upgrade arduino:samd to the latest version") + "\n" +
 			"  " + os.Args[0] + " core upgrade arduino:samd",
 		Run: func(cmd *cobra.Command, args []string) {
 			runUpgradeCommand(cmd.Context(), srv, args, postInstallFlags.DetectSkipPostInstallValue(), postInstallFlags.DetectSkipPreUninstallValue())
@@ -64,7 +65,7 @@ func Upgrade(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rpc.In
 			Instance: inst,
 		})
 		if err != nil {
-			feedback.Fatal(tr("Error retrieving core list: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error retrieving core list: %v", err), feedback.ErrGeneric)
 		}
 
 		targets := []*rpc.Platform{}
@@ -83,7 +84,7 @@ func Upgrade(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rpc.In
 		}
 
 		if len(targets) == 0 {
-			feedback.Print(tr("All the cores are already at the latest version"))
+			feedback.Print(i18n.Tr("All the cores are already at the latest version"))
 			return
 		}
 
@@ -97,20 +98,20 @@ func Upgrade(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rpc.In
 			return
 		}
 		if !platform.GetMetadata().GetIndexed() {
-			feedback.Warning(tr("missing package index for %s, future updates cannot be guaranteed", platform.GetMetadata().GetId()))
+			feedback.Warning(i18n.Tr("missing package index for %s, future updates cannot be guaranteed", platform.GetMetadata().GetId()))
 		}
 	}
 
 	// proceed upgrading, if anything is upgradable
 	platformsRefs, err := arguments.ParseReferences(ctx, srv, args)
 	if err != nil {
-		feedback.Fatal(tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
 	}
 
 	hasBadArguments := false
 	for i, platformRef := range platformsRefs {
 		if platformRef.Version != "" {
-			feedback.Warning(tr("Invalid item %s", args[i]))
+			feedback.Warning(i18n.Tr("Invalid item %s", args[i]))
 			hasBadArguments = true
 			continue
 		}
@@ -132,12 +133,12 @@ func Upgrade(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rpc.In
 				continue
 			}
 
-			feedback.Fatal(tr("Error during upgrade: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error during upgrade: %v", err), feedback.ErrGeneric)
 		}
 	}
 
 	if hasBadArguments {
-		feedback.Fatal(tr("Some upgrades failed, please check the output for details."), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Some upgrades failed, please check the output for details."), feedback.ErrBadArgument)
 	}
 
 	feedback.PrintResult(&platformUpgradeResult{})
diff --git a/internal/cli/daemon/daemon.go b/internal/cli/daemon/daemon.go
index 76c7e9a24ef..3139a66bdde 100644
--- a/internal/cli/daemon/daemon.go
+++ b/internal/cli/daemon/daemon.go
@@ -47,7 +47,7 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configuration) *
 	var daemonPort string
 	daemonCommand := &cobra.Command{
 		Use:     "daemon",
-		Short:   tr("Run the Arduino CLI as a gRPC daemon."),
+		Short:   i18n.Tr("Run the Arduino CLI as a gRPC daemon."),
 		Example: "  " + os.Args[0] + " daemon",
 		Args:    cobra.NoArgs,
 		PreRun: func(cmd *cobra.Command, args []string) {
@@ -73,19 +73,19 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configuration) *
 
 	daemonCommand.Flags().StringVar(&daemonPort,
 		"port", defaultDaemonPort,
-		tr("The TCP port the daemon will listen to"))
+		i18n.Tr("The TCP port the daemon will listen to"))
 	daemonCommand.Flags().BoolVar(&daemonize,
 		"daemonize", false,
-		tr("Do not terminate daemon process if the parent process dies"))
+		i18n.Tr("Do not terminate daemon process if the parent process dies"))
 	daemonCommand.Flags().BoolVar(&debug,
 		"debug", false,
-		tr("Enable debug logging of gRPC calls"))
+		i18n.Tr("Enable debug logging of gRPC calls"))
 	daemonCommand.Flags().StringVar(&debugFile,
 		"debug-file", "",
-		tr("Append debug logging to the specified file"))
+		i18n.Tr("Append debug logging to the specified file"))
 	daemonCommand.Flags().StringSliceVar(&debugFilters,
 		"debug-filter", []string{},
-		tr("Display only the provided gRPC calls"))
+		i18n.Tr("Display only the provided gRPC calls"))
 	return daemonCommand
 }
 
@@ -95,7 +95,7 @@ func runDaemonCommand(srv rpc.ArduinoCoreServiceServer, daemonPort string) {
 	gRPCOptions := []grpc.ServerOption{}
 	if debugFile != "" {
 		if !debug {
-			feedback.Fatal(tr("The flag --debug-file must be used with --debug."), feedback.ErrBadArgument)
+			feedback.Fatal(i18n.Tr("The flag --debug-file must be used with --debug."), feedback.ErrBadArgument)
 		}
 	}
 	if debug {
@@ -103,13 +103,13 @@ func runDaemonCommand(srv rpc.ArduinoCoreServiceServer, daemonPort string) {
 			outFile := paths.New(debugFile)
 			f, err := outFile.Append()
 			if err != nil {
-				feedback.Fatal(tr("Error opening debug logging file: %s", err), feedback.ErrGeneric)
+				feedback.Fatal(i18n.Tr("Error opening debug logging file: %s", err), feedback.ErrGeneric)
 			}
 			defer f.Close()
 			debugStdOut = f
 		} else {
 			if out, _, err := feedback.DirectStreams(); err != nil {
-				feedback.Fatal(tr("Can't write debug log: %s", err), feedback.ErrBadArgument)
+				feedback.Fatal(i18n.Tr("Can't write debug log: %s", err), feedback.ErrBadArgument)
 			} else {
 				debugStdOut = out
 			}
@@ -135,19 +135,19 @@ func runDaemonCommand(srv rpc.ArduinoCoreServiceServer, daemonPort string) {
 		// Invalid port, such as "Foo"
 		var dnsError *net.DNSError
 		if errors.As(err, &dnsError) {
-			feedback.Fatal(tr("Failed to listen on TCP port: %[1]s. %[2]s is unknown name.", daemonPort, dnsError.Name), feedback.ErrBadTCPPortArgument)
+			feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %[1]s. %[2]s is unknown name.", daemonPort, dnsError.Name), feedback.ErrBadTCPPortArgument)
 		}
 		// Invalid port number, such as -1
 		var addrError *net.AddrError
 		if errors.As(err, &addrError) {
-			feedback.Fatal(tr("Failed to listen on TCP port: %[1]s. %[2]s is an invalid port.", daemonPort, addrError.Addr), feedback.ErrBadTCPPortArgument)
+			feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %[1]s. %[2]s is an invalid port.", daemonPort, addrError.Addr), feedback.ErrBadTCPPortArgument)
 		}
 		// Port is already in use
 		var syscallErr *os.SyscallError
 		if errors.As(err, &syscallErr) && errors.Is(syscallErr.Err, syscall.EADDRINUSE) {
-			feedback.Fatal(tr("Failed to listen on TCP port: %s. Address already in use.", daemonPort), feedback.ErrFailedToListenToTCPPort)
+			feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %s. Address already in use.", daemonPort), feedback.ErrFailedToListenToTCPPort)
 		}
-		feedback.Fatal(tr("Failed to listen on TCP port: %[1]s. Unexpected error: %[2]v", daemonPort, err), feedback.ErrFailedToListenToTCPPort)
+		feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %[1]s. Unexpected error: %[2]v", daemonPort, err), feedback.ErrFailedToListenToTCPPort)
 	}
 
 	// We need to retrieve the port used only if the user did not specify it
@@ -158,7 +158,7 @@ func runDaemonCommand(srv rpc.ArduinoCoreServiceServer, daemonPort string) {
 		split := strings.Split(address.String(), ":")
 
 		if len(split) <= 1 {
-			feedback.Fatal(tr("Invalid TCP address: port is missing"), feedback.ErrBadTCPPortArgument)
+			feedback.Fatal(i18n.Tr("Invalid TCP address: port is missing"), feedback.ErrBadTCPPortArgument)
 		}
 
 		daemonPort = split[1]
@@ -185,5 +185,5 @@ func (r daemonResult) Data() interface{} {
 
 func (r daemonResult) String() string {
 	j, _ := json.Marshal(r)
-	return fmt.Sprintln(tr("Daemon is now listening on %s:%s", r.IP, r.Port)) + fmt.Sprintln(string(j))
+	return fmt.Sprintln(i18n.Tr("Daemon is now listening on %s:%s", r.IP, r.Port)) + fmt.Sprintln(string(j))
 }
diff --git a/internal/cli/debug/debug.go b/internal/cli/debug/debug.go
index 3da3c125371..03c8dc8cfcb 100644
--- a/internal/cli/debug/debug.go
+++ b/internal/cli/debug/debug.go
@@ -35,8 +35,6 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `upload` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var (
@@ -51,8 +49,8 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 
 	debugCommand := &cobra.Command{
 		Use:     "debug",
-		Short:   tr("Debug Arduino sketches."),
-		Long:    tr("Debug Arduino sketches. (this command opens an interactive gdb session)"),
+		Short:   i18n.Tr("Debug Arduino sketches."),
+		Long:    i18n.Tr("Debug Arduino sketches. (this command opens an interactive gdb session)"),
 		Example: "  " + os.Args[0] + " debug -b arduino:samd:mkr1000 -P atmel_ice /home/user/Arduino/MySketch",
 		Args:    cobra.MaximumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
@@ -65,9 +63,9 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	portArgs.AddToCommand(debugCommand, srv)
 	programmer.AddToCommand(debugCommand, srv)
 	profileArg.AddToCommand(debugCommand, srv)
-	debugCommand.Flags().StringVar(&interpreter, "interpreter", "console", tr("Debug interpreter e.g.: %s", "console, mi, mi1, mi2, mi3"))
-	debugCommand.Flags().StringVarP(&importDir, "input-dir", "", "", tr("Directory containing binaries for debug."))
-	debugCommand.Flags().BoolVarP(&printInfo, "info", "I", false, tr("Show metadata about the debug session instead of starting the debugger."))
+	debugCommand.Flags().StringVar(&interpreter, "interpreter", "console", i18n.Tr("Debug interpreter e.g.: %s", "console, mi, mi1, mi2, mi3"))
+	debugCommand.Flags().StringVarP(&importDir, "input-dir", "", "", i18n.Tr("Directory containing binaries for debug."))
+	debugCommand.Flags().BoolVarP(&printInfo, "info", "I", false, i18n.Tr("Show metadata about the debug session instead of starting the debugger."))
 
 	return debugCommand
 }
@@ -129,7 +127,7 @@ func runDebugCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args
 			if errors.Is(err, &cmderrors.MissingProgrammerError{}) {
 				errcode = feedback.ErrMissingProgrammer
 			}
-			feedback.Fatal(tr("Error getting Debug info: %v", err), errcode)
+			feedback.Fatal(i18n.Tr("Error getting Debug info: %v", err), errcode)
 		} else {
 			feedback.PrintResult(newDebugInfoResult(res))
 		}
@@ -149,7 +147,7 @@ func runDebugCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args
 			if errors.Is(err, &cmderrors.MissingProgrammerError{}) {
 				errcode = feedback.ErrMissingProgrammer
 			}
-			feedback.Fatal(tr("Error during Debug: %v", err), errcode)
+			feedback.Fatal(i18n.Tr("Error during Debug: %v", err), errcode)
 		}
 
 	}
@@ -182,7 +180,7 @@ func newDebugInfoResult(info *rpc.GetDebugConfigResponse) *debugInfoResult {
 	case "openocd":
 		var openocdConf rpc.DebugOpenOCDServerConfiguration
 		if err := info.GetServerConfiguration().UnmarshalTo(&openocdConf); err != nil {
-			feedback.Fatal(tr("Error during Debug: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error during Debug: %v", err), feedback.ErrGeneric)
 		}
 		serverConfig = &openOcdServerConfigResult{
 			Path:       openocdConf.GetPath(),
@@ -220,24 +218,24 @@ func (r *debugInfoResult) String() string {
 	t := table.New()
 	green := color.New(color.FgHiGreen)
 	dimGreen := color.New(color.FgGreen)
-	t.AddRow(tr("Executable to debug"), table.NewCell(r.Executable, green))
-	t.AddRow(tr("Toolchain type"), table.NewCell(r.Toolchain, green))
-	t.AddRow(tr("Toolchain path"), table.NewCell(r.ToolchainPath, dimGreen))
-	t.AddRow(tr("Toolchain prefix"), table.NewCell(r.ToolchainPrefix, dimGreen))
+	t.AddRow(i18n.Tr("Executable to debug"), table.NewCell(r.Executable, green))
+	t.AddRow(i18n.Tr("Toolchain type"), table.NewCell(r.Toolchain, green))
+	t.AddRow(i18n.Tr("Toolchain path"), table.NewCell(r.ToolchainPath, dimGreen))
+	t.AddRow(i18n.Tr("Toolchain prefix"), table.NewCell(r.ToolchainPrefix, dimGreen))
 	if r.SvdFile != "" {
-		t.AddRow(tr("SVD file path"), table.NewCell(r.SvdFile, dimGreen))
+		t.AddRow(i18n.Tr("SVD file path"), table.NewCell(r.SvdFile, dimGreen))
 	}
 	switch r.Toolchain {
 	case "gcc":
 		// no options available at the moment...
 	default:
 	}
-	t.AddRow(tr("Server type"), table.NewCell(r.Server, green))
-	t.AddRow(tr("Server path"), table.NewCell(r.ServerPath, dimGreen))
+	t.AddRow(i18n.Tr("Server type"), table.NewCell(r.Server, green))
+	t.AddRow(i18n.Tr("Server path"), table.NewCell(r.ServerPath, dimGreen))
 
 	switch r.Server {
 	case "openocd":
-		t.AddRow(tr("Configuration options for %s", r.Server))
+		t.AddRow(i18n.Tr("Configuration options for %s", r.Server))
 		openocdConf := r.ServerConfig.(*openOcdServerConfigResult)
 		if openocdConf.Path != "" {
 			t.AddRow(" - Path", table.NewCell(openocdConf.Path, dimGreen))
@@ -253,7 +251,7 @@ func (r *debugInfoResult) String() string {
 	if custom := r.CustomConfigs; custom != nil {
 		for id, config := range custom {
 			configJson, _ := json.MarshalIndent(config, "", "  ")
-			t.AddRow(tr("Custom configuration for %s:", id))
+			t.AddRow(i18n.Tr("Custom configuration for %s:", id))
 			return t.Render() + "  " + string(configJson)
 		}
 	}
diff --git a/internal/cli/debug/debug_check.go b/internal/cli/debug/debug_check.go
index c16bb13cc25..cb749a2da0e 100644
--- a/internal/cli/debug/debug_check.go
+++ b/internal/cli/debug/debug_check.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -38,7 +39,7 @@ func newDebugCheckCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	)
 	debugCheckCommand := &cobra.Command{
 		Use:     "check",
-		Short:   tr("Check if the given board/programmer combination supports debugging."),
+		Short:   i18n.Tr("Check if the given board/programmer combination supports debugging."),
 		Example: "  " + os.Args[0] + " debug check -b arduino:samd:mkr1000 -P atmel_ice",
 		Run: func(cmd *cobra.Command, args []string) {
 			runDebugCheckCommand(cmd.Context(), srv, &portArgs, &fqbnArg, interpreter, &programmer)
@@ -47,7 +48,7 @@ func newDebugCheckCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	fqbnArg.AddToCommand(debugCheckCommand, srv)
 	portArgs.AddToCommand(debugCheckCommand, srv)
 	programmer.AddToCommand(debugCheckCommand, srv)
-	debugCheckCommand.Flags().StringVar(&interpreter, "interpreter", "console", tr("Debug interpreter e.g.: %s", "console, mi, mi1, mi2, mi3"))
+	debugCheckCommand.Flags().StringVar(&interpreter, "interpreter", "console", i18n.Tr("Debug interpreter e.g.: %s", "console, mi, mi1, mi2, mi3"))
 	return debugCheckCommand
 }
 
@@ -83,7 +84,7 @@ func (d *debugCheckResult) Data() interface{} {
 
 func (d *debugCheckResult) String() string {
 	if d.Result.DebuggingSupported {
-		return tr("The given board/programmer configuration supports debugging.")
+		return i18n.Tr("The given board/programmer configuration supports debugging.")
 	}
-	return tr("The given board/programmer configuration does NOT support debugging.")
+	return i18n.Tr("The given board/programmer configuration does NOT support debugging.")
 }
diff --git a/internal/cli/feedback/feedback.go b/internal/cli/feedback/feedback.go
index db98749bd41..c665f35a0dd 100644
--- a/internal/cli/feedback/feedback.go
+++ b/internal/cli/feedback/feedback.go
@@ -105,8 +105,6 @@ type ErrorResult interface {
 	ErrorString() string
 }
 
-var tr = i18n.Tr
-
 // SetOut can be used to change the out writer at runtime
 func SetOut(out io.Writer) {
 	if formatSelected {
@@ -235,13 +233,13 @@ func PrintResult(res Result) {
 	case JSON:
 		d, err := json.MarshalIndent(augment(res.Data()), "", "  ")
 		if err != nil {
-			Fatal(tr("Error during JSON encoding of the output: %v", err), ErrGeneric)
+			Fatal(i18n.Tr("Error during JSON encoding of the output: %v", err), ErrGeneric)
 		}
 		data = string(d)
 	case MinifiedJSON:
 		d, err := json.Marshal(augment(res.Data()))
 		if err != nil {
-			Fatal(tr("Error during JSON encoding of the output: %v", err), ErrGeneric)
+			Fatal(i18n.Tr("Error during JSON encoding of the output: %v", err), ErrGeneric)
 		}
 		data = string(d)
 	case Text:
diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go
index e03c8166d48..f5178a6382c 100644
--- a/internal/cli/feedback/result/rpc.go
+++ b/internal/cli/feedback/result/rpc.go
@@ -27,8 +27,6 @@ import (
 	semver "go.bug.st/relaxed-semver"
 )
 
-var tr = i18n.Tr
-
 // NewPlatformSummary creates a new result.PlatformSummary from rpc.PlatformSummary
 func NewPlatformSummary(in *rpc.PlatformSummary) *PlatformSummary {
 	if in == nil {
@@ -145,7 +143,7 @@ type PlatformRelease struct {
 
 func (p *PlatformRelease) FormatName() string {
 	if p.Deprecated {
-		return fmt.Sprintf("[%s] %s", tr("DEPRECATED"), p.Name)
+		return fmt.Sprintf("[%s] %s", i18n.Tr("DEPRECATED"), p.Name)
 	}
 	return p.Name
 }
diff --git a/internal/cli/feedback/rpc_progress.go b/internal/cli/feedback/rpc_progress.go
index c9a413a4fdb..0d63d5cd346 100644
--- a/internal/cli/feedback/rpc_progress.go
+++ b/internal/cli/feedback/rpc_progress.go
@@ -18,6 +18,7 @@ package feedback
 import (
 	"sync"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/cmaglie/pb"
 )
@@ -70,7 +71,7 @@ func NewDownloadProgressBarCB() func(*rpc.DownloadProgress) {
 		if end := curr.GetEnd(); end != nil {
 			msg := end.GetMessage()
 			if end.GetSuccess() && msg == "" {
-				msg = tr("downloaded")
+				msg = i18n.Tr("downloaded")
 			}
 			if started {
 				bar.FinishPrintOver(label + " " + msg)
diff --git a/internal/cli/feedback/stdio.go b/internal/cli/feedback/stdio.go
index 87f37f0c227..e279ce2979d 100644
--- a/internal/cli/feedback/stdio.go
+++ b/internal/cli/feedback/stdio.go
@@ -19,6 +19,8 @@ import (
 	"bytes"
 	"errors"
 	"io"
+
+	"github.com/arduino/arduino-cli/internal/i18n"
 )
 
 // DirectStreams returns the underlying io.Writer to directly stream to
@@ -32,7 +34,7 @@ func DirectStreams() (io.Writer, io.Writer, error) {
 		panic("output format not yet selected")
 	}
 	if format != Text {
-		return nil, nil, errors.New(tr("available only in text format"))
+		return nil, nil, errors.New(i18n.Tr("available only in text format"))
 	}
 	return stdOut, stdErr, nil
 }
diff --git a/internal/cli/feedback/terminal.go b/internal/cli/feedback/terminal.go
index 9b60b80cc11..8dc4c09a611 100644
--- a/internal/cli/feedback/terminal.go
+++ b/internal/cli/feedback/terminal.go
@@ -22,6 +22,7 @@ import (
 	"io"
 	"os"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	"github.com/mattn/go-isatty"
 	"golang.org/x/term"
 )
@@ -34,7 +35,7 @@ func InteractiveStreams() (io.Reader, io.Writer, error) {
 		panic("output format not yet selected")
 	}
 	if format != Text {
-		return nil, nil, errors.New(tr("interactive terminal not supported for the '%s' output format", format))
+		return nil, nil, errors.New(i18n.Tr("interactive terminal not supported for the '%s' output format", format))
 	}
 	return os.Stdin, stdOut, nil
 }
@@ -48,7 +49,7 @@ func SetRawModeStdin() error {
 		panic("terminal already in RAW mode")
 	}
 	if !IsInteractive() {
-		return errors.New(tr("not running in a terminal"))
+		return errors.New(i18n.Tr("not running in a terminal"))
 	}
 	old, err := term.MakeRaw(int(os.Stdin.Fd()))
 	if err != nil {
@@ -90,10 +91,10 @@ func IsCI() bool {
 // InputUserField prompts the user to input the provided user field.
 func InputUserField(prompt string, secret bool) (string, error) {
 	if format != Text {
-		return "", errors.New(tr("user input not supported for the '%s' output format", format))
+		return "", errors.New(i18n.Tr("user input not supported for the '%s' output format", format))
 	}
 	if !IsInteractive() {
-		return "", errors.New(tr("user input not supported in non interactive mode"))
+		return "", errors.New(i18n.Tr("user input not supported in non interactive mode"))
 	}
 
 	fmt.Fprintf(stdOut, "%s: ", prompt)
diff --git a/internal/cli/feedback/warn_deprecated.go b/internal/cli/feedback/warn_deprecated.go
index 0a780574d5e..1354ef77269 100644
--- a/internal/cli/feedback/warn_deprecated.go
+++ b/internal/cli/feedback/warn_deprecated.go
@@ -19,6 +19,7 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -35,7 +36,7 @@ func WarnAboutDeprecatedFiles(s *rpc.Sketch) {
 	}
 	if len(files) > 0 {
 		// .pde files are still supported but deprecated, this warning urges the user to rename them
-		msg := tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
+		msg := i18n.Tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
 		for _, f := range files {
 			msg += fmt.Sprintf("\n - %s", f)
 		}
diff --git a/internal/cli/generatedocs/generatedocs.go b/internal/cli/generatedocs/generatedocs.go
index 59bf270c442..d8bdd0a18af 100644
--- a/internal/cli/generatedocs/generatedocs.go
+++ b/internal/cli/generatedocs/generatedocs.go
@@ -35,14 +35,14 @@ var (
 func NewCommand() *cobra.Command {
 	generateDocsCommand := &cobra.Command{
 		Use:     "generate-docs",
-		Short:   tr("Generates bash completion and command manpages."),
-		Long:    tr("Generates bash completion and command manpages."),
+		Short:   i18n.Tr("Generates bash completion and command manpages."),
+		Long:    i18n.Tr("Generates bash completion and command manpages."),
 		Example: "  " + os.Args[0] + " generate-docs bash-completions",
 		Hidden:  true,
 	}
 
 	generateDocsCommand.PersistentFlags().StringVarP(&outputDir, "output-dir", "o", "",
-		tr("Directory where to save generated files. Default is './docs', the directory must exist."))
+		i18n.Tr("Directory where to save generated files. Default is './docs', the directory must exist."))
 	generateDocsCommand.AddCommand(&cobra.Command{
 		Use:  "manpage",
 		Args: cobra.NoArgs,
@@ -77,7 +77,7 @@ func generateManPages(cmd *cobra.Command, args []string) {
 	}
 	logrus.WithField("outputDir", outputDir).Info("Generating manpages")
 	header := &doc.GenManHeader{
-		Title:   tr("ARDUINO COMMAND LINE MANUAL"),
+		Title:   i18n.Tr("ARDUINO COMMAND LINE MANUAL"),
 		Section: "1",
 	}
 	err := doc.GenManTree(cmd.Root(), header, outputDir)
diff --git a/internal/cli/instance/instance.go b/internal/cli/instance/instance.go
index 28a19ad6e5a..316a1b0baf6 100644
--- a/internal/cli/instance/instance.go
+++ b/internal/cli/instance/instance.go
@@ -25,8 +25,6 @@ import (
 	"github.com/arduino/go-paths-helper"
 )
 
-var tr = i18n.Tr
-
 // CreateAndInit return a new initialized instance.
 // If Create fails the CLI prints an error and exits since
 // to execute further operations a valid Instance is mandatory.
@@ -42,7 +40,7 @@ func CreateAndInit(ctx context.Context, srv rpc.ArduinoCoreServiceServer) *rpc.I
 func CreateAndInitWithProfile(ctx context.Context, srv rpc.ArduinoCoreServiceServer, profileName string, sketchPath *paths.Path) (*rpc.Instance, *rpc.SketchProfile) {
 	instance, err := create(ctx, srv)
 	if err != nil {
-		feedback.Fatal(tr("Error creating instance: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error creating instance: %v", err), feedback.ErrGeneric)
 	}
 	profile := InitWithProfile(ctx, srv, instance, profileName, sketchPath)
 	return instance, profile
@@ -81,7 +79,7 @@ func InitWithProfile(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst
 	var profile *rpc.SketchProfile
 	err := srv.Init(initReq, commands.InitStreamResponseToCallbackFunction(ctx, func(res *rpc.InitResponse) error {
 		if st := res.GetError(); st != nil {
-			feedback.Warning(tr("Error initializing instance: %v", st.GetMessage()))
+			feedback.Warning(i18n.Tr("Error initializing instance: %v", st.GetMessage()))
 		}
 
 		if progress := res.GetInitProgress(); progress != nil {
@@ -99,7 +97,7 @@ func InitWithProfile(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst
 		return nil
 	}))
 	if err != nil {
-		feedback.Warning(tr("Error initializing instance: %v", err))
+		feedback.Warning(i18n.Tr("Error initializing instance: %v", err))
 	}
 
 	return profile
diff --git a/internal/cli/lib/args.go b/internal/cli/lib/args.go
index 3d3546a0c7e..63d0f7b1696 100644
--- a/internal/cli/lib/args.go
+++ b/internal/cli/lib/args.go
@@ -17,9 +17,10 @@ package lib
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"strings"
 
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 )
 
@@ -45,12 +46,12 @@ func ParseLibraryReferenceArg(arg string) (*LibraryReferenceArg, error) {
 	// TODO: check library Name constraints
 	// TODO: check library Version constraints
 	if tokens[0] == "" {
-		return nil, fmt.Errorf(tr("invalid empty library name"))
+		return nil, errors.New(i18n.Tr("invalid empty library name"))
 	}
 	ret.Name = tokens[0]
 	if len(tokens) > 1 {
 		if tokens[1] == "" {
-			return nil, fmt.Errorf(tr("invalid empty library version: %s"), arg)
+			return nil, errors.New(i18n.Tr("invalid empty library version: %s", arg))
 		}
 		ret.Version = tokens[1]
 	}
diff --git a/internal/cli/lib/check_deps.go b/internal/cli/lib/check_deps.go
index 8e18e800515..48f57291d63 100644
--- a/internal/cli/lib/check_deps.go
+++ b/internal/cli/lib/check_deps.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/fatih/color"
 	"github.com/sirupsen/logrus"
@@ -34,12 +35,12 @@ import (
 func initDepsCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var noOverwrite bool
 	depsCommand := &cobra.Command{
-		Use:   fmt.Sprintf("deps %s[@%s]...", tr("LIBRARY"), tr("VERSION_NUMBER")),
-		Short: tr("Check dependencies status for the specified library."),
-		Long:  tr("Check dependencies status for the specified library."),
+		Use:   fmt.Sprintf("deps %s[@%s]...", i18n.Tr("LIBRARY"), i18n.Tr("VERSION_NUMBER")),
+		Short: i18n.Tr("Check dependencies status for the specified library."),
+		Long:  i18n.Tr("Check dependencies status for the specified library."),
 		Example: "" +
-			"  " + os.Args[0] + " lib deps AudioZero       # " + tr("for the latest version.") + "\n" +
-			"  " + os.Args[0] + " lib deps AudioZero@1.0.0 # " + tr("for the specific version."),
+			"  " + os.Args[0] + " lib deps AudioZero       # " + i18n.Tr("for the latest version.") + "\n" +
+			"  " + os.Args[0] + " lib deps AudioZero@1.0.0 # " + i18n.Tr("for the specific version."),
 		Args: cobra.ExactArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
 			runDepsCommand(cmd.Context(), srv, args, noOverwrite)
@@ -48,7 +49,7 @@ func initDepsCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 			return arguments.GetInstalledLibraries(cmd.Context(), srv), cobra.ShellCompDirectiveDefault
 		},
 	}
-	depsCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, tr("Do not try to update library dependencies if already installed."))
+	depsCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, i18n.Tr("Do not try to update library dependencies if already installed."))
 	return depsCommand
 }
 
@@ -58,7 +59,7 @@ func runDepsCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args
 	logrus.Info("Executing `arduino-cli lib deps`")
 	libRef, err := ParseLibraryReferenceArgAndAdjustCase(ctx, srv, instance, args[0])
 	if err != nil {
-		feedback.Fatal(tr("Arguments error: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Arguments error: %v", err), feedback.ErrBadArgument)
 	}
 
 	deps, err := srv.LibraryResolveDependencies(ctx, &rpc.LibraryResolveDependenciesRequest{
@@ -68,7 +69,7 @@ func runDepsCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args
 		DoNotUpdateInstalledLibraries: noOverwrite,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error resolving dependencies for %[1]s: %[2]s", libRef, err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error resolving dependencies for %[1]s: %[2]s", libRef, err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(&checkDepResult{deps: result.NewLibraryResolveDependenciesResponse(deps)})
@@ -114,13 +115,13 @@ func outputDep(dep *result.LibraryDependencyStatus) string {
 	red := color.New(color.FgRed)
 	yellow := color.New(color.FgYellow)
 	if dep.VersionInstalled == "" {
-		res += tr("%s must be installed.",
+		res += i18n.Tr("%s must be installed.",
 			red.Sprintf("✕ %s %s", dep.Name, dep.VersionRequired))
 	} else if dep.VersionInstalled == dep.VersionRequired {
-		res += tr("%s is already installed.",
+		res += i18n.Tr("%s is already installed.",
 			green.Sprintf("✓ %s %s", dep.Name, dep.VersionRequired))
 	} else {
-		res += tr("%[1]s is required but %[2]s is currently installed.",
+		res += i18n.Tr("%[1]s is required but %[2]s is currently installed.",
 			yellow.Sprintf("✕ %s %s", dep.Name, dep.VersionRequired),
 			yellow.Sprintf("%s", dep.VersionInstalled))
 	}
diff --git a/internal/cli/lib/download.go b/internal/cli/lib/download.go
index 562f8b07bb9..511d38291e8 100644
--- a/internal/cli/lib/download.go
+++ b/internal/cli/lib/download.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,12 +32,12 @@ import (
 
 func initDownloadCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	downloadCommand := &cobra.Command{
-		Use:   fmt.Sprintf("download [%s]...", tr("LIBRARY_NAME")),
-		Short: tr("Downloads one or more libraries without installing them."),
-		Long:  tr("Downloads one or more libraries without installing them."),
+		Use:   fmt.Sprintf("download [%s]...", i18n.Tr("LIBRARY_NAME")),
+		Short: i18n.Tr("Downloads one or more libraries without installing them."),
+		Long:  i18n.Tr("Downloads one or more libraries without installing them."),
 		Example: "" +
-			"  " + os.Args[0] + " lib download AudioZero       # " + tr("for the latest version.") + "\n" +
-			"  " + os.Args[0] + " lib download AudioZero@1.0.0 # " + tr("for a specific version."),
+			"  " + os.Args[0] + " lib download AudioZero       # " + i18n.Tr("for the latest version.") + "\n" +
+			"  " + os.Args[0] + " lib download AudioZero@1.0.0 # " + i18n.Tr("for a specific version."),
 		Args: cobra.MinimumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
 			runDownloadCommand(cmd.Context(), srv, args)
@@ -54,7 +55,7 @@ func runDownloadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, a
 
 	refs, err := ParseLibraryReferenceArgsAndAdjustCase(ctx, srv, instance, args)
 	if err != nil {
-		feedback.Fatal(tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
 	}
 
 	for _, library := range refs {
@@ -65,7 +66,7 @@ func runDownloadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, a
 		}
 		stream := commands.LibraryDownloadStreamResponseToCallbackFunction(ctx, feedback.ProgressBar())
 		if err := srv.LibraryDownload(libraryDownloadRequest, stream); err != nil {
-			feedback.Fatal(tr("Error downloading %[1]s: %[2]v", library, err), feedback.ErrNetwork)
+			feedback.Fatal(i18n.Tr("Error downloading %[1]s: %[2]v", library, err), feedback.ErrNetwork)
 		}
 	}
 }
diff --git a/internal/cli/lib/examples.go b/internal/cli/lib/examples.go
index ff24e3616cb..3b418809dfc 100644
--- a/internal/cli/lib/examples.go
+++ b/internal/cli/lib/examples.go
@@ -26,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/fatih/color"
@@ -39,9 +40,9 @@ var (
 
 func initExamplesCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	examplesCommand := &cobra.Command{
-		Use:     fmt.Sprintf("examples [%s]", tr("LIBRARY_NAME")),
-		Short:   tr("Shows the list of the examples for libraries."),
-		Long:    tr("Shows the list of the examples for libraries. A name may be given as argument to search a specific library."),
+		Use:     fmt.Sprintf("examples [%s]", i18n.Tr("LIBRARY_NAME")),
+		Short:   i18n.Tr("Shows the list of the examples for libraries."),
+		Long:    i18n.Tr("Shows the list of the examples for libraries. A name may be given as argument to search a specific library."),
 		Example: "  " + os.Args[0] + " lib examples Wire",
 		Args:    cobra.MaximumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
@@ -71,7 +72,7 @@ func runExamplesCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, a
 		Fqbn:     fqbn.String(),
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error getting libraries info: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error getting libraries info: %v", err), feedback.ErrGeneric)
 	}
 
 	found := []*libraryExamples{}
@@ -104,7 +105,7 @@ func (ir libraryExamplesResult) Data() interface{} {
 
 func (ir libraryExamplesResult) String() string {
 	if ir.Examples == nil || len(ir.Examples) == 0 {
-		return tr("No libraries found.")
+		return i18n.Tr("No libraries found.")
 	}
 
 	sort.Slice(ir.Examples, func(i, j int) bool {
@@ -119,7 +120,7 @@ func (ir libraryExamplesResult) String() string {
 		} else if lib.Library.Location != result.LibraryLocationUser {
 			name += " (" + string(lib.Library.Location) + ")"
 		}
-		r := tr("Examples for library %s", color.GreenString("%s", name)) + "\n"
+		r := i18n.Tr("Examples for library %s", color.GreenString("%s", name)) + "\n"
 		sort.Slice(lib.Examples, func(i, j int) bool {
 			return strings.ToLower(lib.Examples[i]) < strings.ToLower(lib.Examples[j])
 		})
diff --git a/internal/cli/lib/install.go b/internal/cli/lib/install.go
index fbde0cf8a6b..29ae88ccdcd 100644
--- a/internal/cli/lib/install.go
+++ b/internal/cli/lib/install.go
@@ -25,6 +25,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/arduino-cli/version"
 	"github.com/arduino/go-paths-helper"
@@ -41,14 +42,14 @@ func initInstallCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configur
 	var useBuiltinLibrariesDir bool
 	enableUnsafeInstall := settings.GetLibrary().GetEnableUnsafeInstall()
 	installCommand := &cobra.Command{
-		Use:   fmt.Sprintf("install %s[@%s]...", tr("LIBRARY"), tr("VERSION_NUMBER")),
-		Short: tr("Installs one or more specified libraries into the system."),
-		Long:  tr("Installs one or more specified libraries into the system."),
+		Use:   fmt.Sprintf("install %s[@%s]...", i18n.Tr("LIBRARY"), i18n.Tr("VERSION_NUMBER")),
+		Short: i18n.Tr("Installs one or more specified libraries into the system."),
+		Long:  i18n.Tr("Installs one or more specified libraries into the system."),
 		Example: "" +
-			"  " + os.Args[0] + " lib install AudioZero       # " + tr("for the latest version.") + "\n" +
-			"  " + os.Args[0] + " lib install AudioZero@1.0.0 # " + tr("for the specific version.") + "\n" +
+			"  " + os.Args[0] + " lib install AudioZero       # " + i18n.Tr("for the latest version.") + "\n" +
+			"  " + os.Args[0] + " lib install AudioZero@1.0.0 # " + i18n.Tr("for the specific version.") + "\n" +
 			"  " + os.Args[0] + " lib install --git-url https://github.com/arduino-libraries/WiFi101.git https://github.com/arduino-libraries/ArduinoBLE.git\n" +
-			"  " + os.Args[0] + " lib install --git-url https://github.com/arduino-libraries/WiFi101.git#0.16.0 # " + tr("for the specific version.") + "\n" +
+			"  " + os.Args[0] + " lib install --git-url https://github.com/arduino-libraries/WiFi101.git#0.16.0 # " + i18n.Tr("for the specific version.") + "\n" +
 			"  " + os.Args[0] + " lib install --zip-path /path/to/WiFi101.zip /path/to/ArduinoBLE.zip\n",
 		Args: cobra.MinimumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
@@ -58,11 +59,11 @@ func initInstallCommand(srv rpc.ArduinoCoreServiceServer, settings *rpc.Configur
 			return arguments.GetInstallableLibs(cmd.Context(), srv), cobra.ShellCompDirectiveDefault
 		},
 	}
-	installCommand.Flags().BoolVar(&noDeps, "no-deps", false, tr("Do not install dependencies."))
-	installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, tr("Do not overwrite already installed libraries."))
-	installCommand.Flags().BoolVar(&gitURL, "git-url", false, tr("Enter git url for libraries hosted on repositories"))
-	installCommand.Flags().BoolVar(&zipPath, "zip-path", false, tr("Enter a path to zip file"))
-	installCommand.Flags().BoolVar(&useBuiltinLibrariesDir, "install-in-builtin-dir", false, tr("Install libraries in the IDE-Builtin directory"))
+	installCommand.Flags().BoolVar(&noDeps, "no-deps", false, i18n.Tr("Do not install dependencies."))
+	installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, i18n.Tr("Do not overwrite already installed libraries."))
+	installCommand.Flags().BoolVar(&gitURL, "git-url", false, i18n.Tr("Enter git url for libraries hosted on repositories"))
+	installCommand.Flags().BoolVar(&zipPath, "zip-path", false, i18n.Tr("Enter a path to zip file"))
+	installCommand.Flags().BoolVar(&useBuiltinLibrariesDir, "install-in-builtin-dir", false, i18n.Tr("Install libraries in the IDE-Builtin directory"))
 	return installCommand
 }
 
@@ -78,12 +79,12 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 				split := strings.Split(version.VersionInfo.VersionString, ".")
 				documentationURL = fmt.Sprintf("https://arduino.github.io/arduino-cli/%s.%s/configuration/#configuration-keys", split[0], split[1])
 			}
-			feedback.Fatal(tr("--git-url and --zip-path are disabled by default, for more information see: %v", documentationURL), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("--git-url and --zip-path are disabled by default, for more information see: %v", documentationURL), feedback.ErrGeneric)
 		}
-		feedback.Print(tr("--git-url and --zip-path flags allow installing untrusted files, use it at your own risk."))
+		feedback.Print(i18n.Tr("--git-url and --zip-path flags allow installing untrusted files, use it at your own risk."))
 
 		if useBuiltinLibrariesDir {
-			feedback.Fatal(tr("--git-url or --zip-path can't be used with --install-in-builtin-dir"), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("--git-url or --zip-path can't be used with --install-in-builtin-dir"), feedback.ErrGeneric)
 		}
 	}
 
@@ -96,7 +97,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 			}
 			stream := commands.ZipLibraryInstallStreamResponseToCallbackFunction(ctx, feedback.TaskProgress())
 			if err := srv.ZipLibraryInstall(req, stream); err != nil {
-				feedback.Fatal(tr("Error installing Zip Library: %v", err), feedback.ErrGeneric)
+				feedback.Fatal(i18n.Tr("Error installing Zip Library: %v", err), feedback.ErrGeneric)
 			}
 		}
 		return
@@ -107,7 +108,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 			if url == "." {
 				wd, err := paths.Getwd()
 				if err != nil {
-					feedback.Fatal(tr("Couldn't get current working directory: %v", err), feedback.ErrGeneric)
+					feedback.Fatal(i18n.Tr("Couldn't get current working directory: %v", err), feedback.ErrGeneric)
 				}
 				url = wd.String()
 			}
@@ -118,7 +119,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 			}
 			stream := commands.GitLibraryInstallStreamResponseToCallbackFunction(ctx, feedback.TaskProgress())
 			if err := srv.GitLibraryInstall(req, stream); err != nil {
-				feedback.Fatal(tr("Error installing Git Library: %v", err), feedback.ErrGeneric)
+				feedback.Fatal(i18n.Tr("Error installing Git Library: %v", err), feedback.ErrGeneric)
 			}
 		}
 		return
@@ -126,7 +127,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 
 	libRefs, err := ParseLibraryReferenceArgsAndAdjustCase(ctx, srv, instance, args)
 	if err != nil {
-		feedback.Fatal(tr("Arguments error: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Arguments error: %v", err), feedback.ErrBadArgument)
 	}
 
 	for _, libRef := range libRefs {
@@ -144,7 +145,7 @@ func runInstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 		}
 		stream := commands.LibraryInstallStreamResponseToCallbackFunction(ctx, feedback.ProgressBar(), feedback.TaskProgress())
 		if err := srv.LibraryInstall(libraryInstallRequest, stream); err != nil {
-			feedback.Fatal(tr("Error installing %s: %v", libRef.Name, err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error installing %s: %v", libRef.Name, err), feedback.ErrGeneric)
 		}
 	}
 }
diff --git a/internal/cli/lib/lib.go b/internal/cli/lib/lib.go
index 5aa89cee8dd..45081bda391 100644
--- a/internal/cli/lib/lib.go
+++ b/internal/cli/lib/lib.go
@@ -23,14 +23,12 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `lib` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer, defaultSettings *rpc.Configuration) *cobra.Command {
 	libCommand := &cobra.Command{
 		Use:   "lib",
-		Short: tr("Arduino commands about libraries."),
-		Long:  tr("Arduino commands about libraries."),
+		Short: i18n.Tr("Arduino commands about libraries."),
+		Long:  i18n.Tr("Arduino commands about libraries."),
 		Example: "" +
 			"  " + os.Args[0] + " lib install AudioZero\n" +
 			"  " + os.Args[0] + " lib update-index",
diff --git a/internal/cli/lib/list.go b/internal/cli/lib/list.go
index f764df4985c..d316e8b3756 100644
--- a/internal/cli/lib/list.go
+++ b/internal/cli/lib/list.go
@@ -26,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/table"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -35,9 +36,9 @@ func initListCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var all bool
 	var updatable bool
 	listCommand := &cobra.Command{
-		Use:   fmt.Sprintf("list [%s]", tr("LIBNAME")),
-		Short: tr("Shows a list of installed libraries."),
-		Long: tr(`Shows a list of installed libraries.
+		Use:   fmt.Sprintf("list [%s]", i18n.Tr("LIBNAME")),
+		Short: i18n.Tr("Shows a list of installed libraries."),
+		Long: i18n.Tr(`Shows a list of installed libraries.
 
 If the LIBNAME parameter is specified the listing is limited to that specific
 library. By default the libraries provided as built-in by platforms/core are
@@ -51,9 +52,9 @@ not listed, they can be listed by adding the --all flag.`),
 			List(ctx, srv, instance, args, all, updatable)
 		},
 	}
-	listCommand.Flags().BoolVar(&all, "all", false, tr("Include built-in libraries (from platforms and IDE) in listing."))
+	listCommand.Flags().BoolVar(&all, "all", false, i18n.Tr("Include built-in libraries (from platforms and IDE) in listing."))
 	fqbn.AddToCommand(listCommand, srv)
-	listCommand.Flags().BoolVar(&updatable, "updatable", false, tr("List updatable libraries."))
+	listCommand.Flags().BoolVar(&updatable, "updatable", false, i18n.Tr("List updatable libraries."))
 	return listCommand
 }
 
@@ -87,7 +88,7 @@ func GetList(ctx context.Context, srv rpc.ArduinoCoreServiceServer, instance *rp
 		Fqbn:      fqbn.String(),
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error listing libraries: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error listing libraries: %v", err), feedback.ErrGeneric)
 	}
 
 	libs := []*rpc.InstalledLibrary{}
@@ -124,9 +125,9 @@ func (ir installedResult) Data() interface{} {
 func (ir installedResult) String() string {
 	if len(ir.InstalledLibs) == 0 {
 		if ir.onlyUpdates {
-			return tr("No libraries update is available.")
+			return i18n.Tr("No libraries update is available.")
 		}
-		return tr("No libraries installed.")
+		return i18n.Tr("No libraries installed.")
 	}
 	sort.Slice(ir.InstalledLibs, func(i, j int) bool {
 		return strings.ToLower(ir.InstalledLibs[i].Library.Name) < strings.ToLower(ir.InstalledLibs[j].Library.Name) ||
@@ -134,7 +135,7 @@ func (ir installedResult) String() string {
 	})
 
 	t := table.New()
-	t.SetHeader(tr("Name"), tr("Installed"), tr("Available"), tr("Location"), tr("Description"))
+	t.SetHeader(i18n.Tr("Name"), i18n.Tr("Installed"), i18n.Tr("Available"), i18n.Tr("Location"), i18n.Tr("Description"))
 	t.SetColumnWidthMode(1, table.Average)
 	t.SetColumnWidthMode(2, table.Average)
 	t.SetColumnWidthMode(4, table.Average)
diff --git a/internal/cli/lib/search.go b/internal/cli/lib/search.go
index 94780be95c4..7103c5d9472 100644
--- a/internal/cli/lib/search.go
+++ b/internal/cli/lib/search.go
@@ -26,6 +26,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -35,9 +36,9 @@ func initSearchCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var namesOnly bool
 	var omitReleasesDetails bool
 	searchCommand := &cobra.Command{
-		Use:   fmt.Sprintf("search [%s ...]", tr("SEARCH_TERM")),
-		Short: tr("Searches for one or more libraries matching a query."),
-		Long: tr(`Search for libraries matching zero or more search terms.
+		Use:   fmt.Sprintf("search [%s ...]", i18n.Tr("SEARCH_TERM")),
+		Short: i18n.Tr("Searches for one or more libraries matching a query."),
+		Long: i18n.Tr(`Search for libraries matching zero or more search terms.
 
 All searches are performed in a case-insensitive fashion. Queries containing
 multiple search terms will return only libraries that match all of the terms.
@@ -80,21 +81,21 @@ In addition to the fields listed above, QV terms can use these qualifiers:
  - Version
  - Website
 		`),
-		Example: "  " + os.Args[0] + " lib search audio                               # " + tr("basic search for \"audio\"") + "\n" +
-			"  " + os.Args[0] + " lib search name:buzzer                         # " + tr("libraries with \"buzzer\" in the Name field") + "\n" +
-			"  " + os.Args[0] + " lib search name=pcf8523                        # " + tr("libraries with a Name exactly matching \"pcf8523\"") + "\n" +
-			"  " + os.Args[0] + " lib search \"author:\\\"Daniel Garcia\\\"\"          # " + tr("libraries authored by Daniel Garcia") + "\n" +
-			"  " + os.Args[0] + " lib search author=Adafruit name:gfx            # " + tr("libraries authored only by Adafruit with \"gfx\" in their Name") + "\n" +
-			"  " + os.Args[0] + " lib search esp32 display maintainer=espressif  # " + tr("basic search for \"esp32\" and \"display\" limited to official Maintainer") + "\n" +
-			"  " + os.Args[0] + " lib search dependencies:IRremote               # " + tr("libraries that depend on at least \"IRremote\"") + "\n" +
-			"  " + os.Args[0] + " lib search dependencies=IRremote               # " + tr("libraries that depend only on \"IRremote\"") + "\n",
+		Example: "  " + os.Args[0] + " lib search audio                               # " + i18n.Tr("basic search for \"audio\"") + "\n" +
+			"  " + os.Args[0] + " lib search name:buzzer                         # " + i18n.Tr("libraries with \"buzzer\" in the Name field") + "\n" +
+			"  " + os.Args[0] + " lib search name=pcf8523                        # " + i18n.Tr("libraries with a Name exactly matching \"pcf8523\"") + "\n" +
+			"  " + os.Args[0] + " lib search \"author:\\\"Daniel Garcia\\\"\"          # " + i18n.Tr("libraries authored by Daniel Garcia") + "\n" +
+			"  " + os.Args[0] + " lib search author=Adafruit name:gfx            # " + i18n.Tr("libraries authored only by Adafruit with \"gfx\" in their Name") + "\n" +
+			"  " + os.Args[0] + " lib search esp32 display maintainer=espressif  # " + i18n.Tr("basic search for \"esp32\" and \"display\" limited to official Maintainer") + "\n" +
+			"  " + os.Args[0] + " lib search dependencies:IRremote               # " + i18n.Tr("libraries that depend on at least \"IRremote\"") + "\n" +
+			"  " + os.Args[0] + " lib search dependencies=IRremote               # " + i18n.Tr("libraries that depend only on \"IRremote\"") + "\n",
 		Args: cobra.ArbitraryArgs,
 		Run: func(cmd *cobra.Command, args []string) {
 			runSearchCommand(cmd.Context(), srv, args, namesOnly, omitReleasesDetails)
 		},
 	}
-	searchCommand.Flags().BoolVar(&namesOnly, "names", false, tr("Show library names only."))
-	searchCommand.Flags().BoolVar(&omitReleasesDetails, "omit-releases-details", false, tr("Omit library details far all versions except the latest (produce a more compact JSON output)."))
+	searchCommand.Flags().BoolVar(&namesOnly, "names", false, i18n.Tr("Show library names only."))
+	searchCommand.Flags().BoolVar(&omitReleasesDetails, "omit-releases-details", false, i18n.Tr("Omit library details far all versions except the latest (produce a more compact JSON output)."))
 	return searchCommand
 }
 
@@ -109,7 +110,7 @@ func runSearchCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 	stream, res := commands.UpdateLibrariesIndexStreamResponseToCallbackFunction(ctx, feedback.ProgressBar())
 	req := &rpc.UpdateLibrariesIndexRequest{Instance: inst, UpdateIfOlderThanSecs: int64(indexUpdateInterval.Seconds())}
 	if err := srv.UpdateLibrariesIndex(req, stream); err != nil {
-		feedback.Fatal(tr("Error updating library index: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error updating library index: %v", err), feedback.ErrGeneric)
 	}
 	if res().GetLibrariesIndex().GetStatus() == rpc.IndexUpdateReport_STATUS_UPDATED {
 		instance.Init(ctx, srv, inst)
@@ -122,7 +123,7 @@ func runSearchCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 		OmitReleasesDetails: omitReleasesDetails,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error searching for Libraries: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error searching for Libraries: %v", err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(librarySearchResult{
@@ -164,23 +165,23 @@ func (res librarySearchResult) Data() interface{} {
 func (res librarySearchResult) String() string {
 	results := res.results.Libraries
 	if len(results) == 0 {
-		return tr("No libraries matching your search.")
+		return i18n.Tr("No libraries matching your search.")
 	}
 
 	var out strings.Builder
 
 	if res.results.Status == result.LibrarySearchStatusFailed {
-		out.WriteString(tr("No libraries matching your search.\nDid you mean...\n"))
+		out.WriteString(i18n.Tr("No libraries matching your search.\nDid you mean...\n"))
 	}
 
 	for _, lib := range results {
 		if res.results.Status == result.LibrarySearchStatusSuccess {
-			out.WriteString(tr(`Name: "%s"`, lib.Name) + "\n")
+			out.WriteString(i18n.Tr(`Name: "%s"`, lib.Name) + "\n")
 			if res.namesOnly {
 				continue
 			}
 		} else {
-			out.WriteString(fmt.Sprintf("%s\n", lib.Name))
+			out.WriteString(lib.Name + "\n")
 			continue
 		}
 
@@ -195,23 +196,23 @@ func (res librarySearchResult) String() string {
 			}
 		}
 
-		out.WriteString(fmt.Sprintf("  "+tr("Author: %s")+"\n", latest.Author))
-		out.WriteString(fmt.Sprintf("  "+tr("Maintainer: %s")+"\n", latest.Maintainer))
-		out.WriteString(fmt.Sprintf("  "+tr("Sentence: %s")+"\n", latest.Sentence))
-		out.WriteString(fmt.Sprintf("  "+tr("Paragraph: %s")+"\n", latest.Paragraph))
-		out.WriteString(fmt.Sprintf("  "+tr("Website: %s")+"\n", latest.Website))
+		out.WriteString("  " + i18n.Tr("Author: %s", latest.Author) + "\n")
+		out.WriteString("  " + i18n.Tr("Maintainer: %s", latest.Maintainer) + "\n")
+		out.WriteString("  " + i18n.Tr("Sentence: %s", latest.Sentence) + "\n")
+		out.WriteString("  " + i18n.Tr("Paragraph: %s", latest.Paragraph) + "\n")
+		out.WriteString("  " + i18n.Tr("Website: %s", latest.Website) + "\n")
 		if latest.License != "" {
-			out.WriteString(fmt.Sprintf("  "+tr("License: %s")+"\n", latest.License))
+			out.WriteString("  " + i18n.Tr("License: %s", latest.License) + "\n")
 		}
-		out.WriteString(fmt.Sprintf("  "+tr("Category: %s")+"\n", latest.Category))
-		out.WriteString(fmt.Sprintf("  "+tr("Architecture: %s")+"\n", strings.Join(latest.Architectures, ", ")))
-		out.WriteString(fmt.Sprintf("  "+tr("Types: %s")+"\n", strings.Join(latest.Types, ", ")))
-		out.WriteString(fmt.Sprintf("  "+tr("Versions: %s")+"\n", strings.ReplaceAll(fmt.Sprint(lib.AvailableVersions), " ", ", ")))
+		out.WriteString("  " + i18n.Tr("Category: %s", latest.Category) + "\n")
+		out.WriteString("  " + i18n.Tr("Architecture: %s", strings.Join(latest.Architectures, ", ")) + "\n")
+		out.WriteString("  " + i18n.Tr("Types: %s", strings.Join(latest.Types, ", ")) + "\n")
+		out.WriteString("  " + i18n.Tr("Versions: %s", strings.ReplaceAll(fmt.Sprint(lib.AvailableVersions), " ", ", ")) + "\n")
 		if len(latest.ProvidesIncludes) > 0 {
-			out.WriteString(fmt.Sprintf("  "+tr("Provides includes: %s")+"\n", strings.Join(latest.ProvidesIncludes, ", ")))
+			out.WriteString("  " + i18n.Tr("Provides includes: %s", strings.Join(latest.ProvidesIncludes, ", ")) + "\n")
 		}
 		if len(latest.Dependencies) > 0 {
-			out.WriteString(fmt.Sprintf("  "+tr("Dependencies: %s")+"\n", strings.Join(deps, ", ")))
+			out.WriteString("  " + i18n.Tr("Dependencies: %s", strings.Join(deps, ", ")) + "\n")
 		}
 	}
 
diff --git a/internal/cli/lib/uninstall.go b/internal/cli/lib/uninstall.go
index 07ca7248db2..35855ad47fa 100644
--- a/internal/cli/lib/uninstall.go
+++ b/internal/cli/lib/uninstall.go
@@ -24,6 +24,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,9 +32,9 @@ import (
 
 func initUninstallCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	uninstallCommand := &cobra.Command{
-		Use:     fmt.Sprintf("uninstall %s...", tr("LIBRARY_NAME")),
-		Short:   tr("Uninstalls one or more libraries."),
-		Long:    tr("Uninstalls one or more libraries."),
+		Use:     fmt.Sprintf("uninstall %s...", i18n.Tr("LIBRARY_NAME")),
+		Short:   i18n.Tr("Uninstalls one or more libraries."),
+		Long:    i18n.Tr("Uninstalls one or more libraries."),
 		Example: "  " + os.Args[0] + " lib uninstall AudioZero",
 		Args:    cobra.MinimumNArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
@@ -52,7 +53,7 @@ func runUninstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer,
 
 	refs, err := ParseLibraryReferenceArgsAndAdjustCase(ctx, srv, instance, args)
 	if err != nil {
-		feedback.Fatal(tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
+		feedback.Fatal(i18n.Tr("Invalid argument passed: %v", err), feedback.ErrBadArgument)
 	}
 
 	for _, library := range refs {
@@ -63,7 +64,7 @@ func runUninstallCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer,
 		}
 		stream := commands.LibraryUninstallStreamResponseToCallbackFunction(ctx, feedback.TaskProgress())
 		if err := srv.LibraryUninstall(req, stream); err != nil {
-			feedback.Fatal(tr("Error uninstalling %[1]s: %[2]v", library, err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error uninstalling %[1]s: %[2]v", library, err), feedback.ErrGeneric)
 		}
 	}
 
diff --git a/internal/cli/lib/update_index.go b/internal/cli/lib/update_index.go
index a9c93240b10..8bdb42e2af9 100644
--- a/internal/cli/lib/update_index.go
+++ b/internal/cli/lib/update_index.go
@@ -23,6 +23,7 @@ import (
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/feedback/result"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,8 +32,8 @@ import (
 func initUpdateIndexCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	updateIndexCommand := &cobra.Command{
 		Use:     "update-index",
-		Short:   tr("Updates the libraries index."),
-		Long:    tr("Updates the libraries index to the latest version."),
+		Short:   i18n.Tr("Updates the libraries index."),
+		Long:    i18n.Tr("Updates the libraries index to the latest version."),
 		Example: "  " + os.Args[0] + " lib update-index",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
@@ -55,7 +56,7 @@ func UpdateIndex(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rp
 	req := &rpc.UpdateLibrariesIndexRequest{Instance: inst}
 	stream, resp := commands.UpdateLibrariesIndexStreamResponseToCallbackFunction(ctx, feedback.ProgressBar())
 	if err := srv.UpdateLibrariesIndex(req, stream); err != nil {
-		feedback.Fatal(tr("Error updating library index: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error updating library index: %v", err), feedback.ErrGeneric)
 	}
 	return resp()
 }
diff --git a/internal/cli/lib/upgrade.go b/internal/cli/lib/upgrade.go
index bb0da0caaea..008eea8fdb9 100644
--- a/internal/cli/lib/upgrade.go
+++ b/internal/cli/lib/upgrade.go
@@ -23,6 +23,7 @@ import (
 	"github.com/arduino/arduino-cli/commands"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
 	"github.com/arduino/arduino-cli/internal/cli/instance"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -31,8 +32,8 @@ import (
 func initUpgradeCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	upgradeCommand := &cobra.Command{
 		Use:   "upgrade",
-		Short: tr("Upgrades installed libraries."),
-		Long:  tr("This command upgrades an installed library to the latest available version. Multiple libraries can be passed separated by a space. If no arguments are provided, the command will upgrade all the installed libraries where an update is available."),
+		Short: i18n.Tr("Upgrades installed libraries."),
+		Long:  i18n.Tr("This command upgrades an installed library to the latest available version. Multiple libraries can be passed separated by a space. If no arguments are provided, the command will upgrade all the installed libraries where an update is available."),
 		Example: "  " + os.Args[0] + " lib upgrade \n" +
 			"  " + os.Args[0] + " lib upgrade Audio\n" +
 			"  " + os.Args[0] + " lib upgrade Audio ArduinoJson",
@@ -71,7 +72,7 @@ func Upgrade(ctx context.Context, srv rpc.ArduinoCoreServiceServer, instance *rp
 	}
 
 	if upgradeErr != nil {
-		feedback.Fatal(fmt.Sprintf("%s: %v", tr("Error upgrading libraries"), upgradeErr), feedback.ErrGeneric)
+		feedback.Fatal(fmt.Sprintf("%s: %v", i18n.Tr("Error upgrading libraries"), upgradeErr), feedback.ErrGeneric)
 	}
 
 	logrus.Info("Done")
diff --git a/internal/cli/monitor/monitor.go b/internal/cli/monitor/monitor.go
index eb237521445..3ee32524256 100644
--- a/internal/cli/monitor/monitor.go
+++ b/internal/cli/monitor/monitor.go
@@ -40,8 +40,6 @@ import (
 	"go.bug.st/cleanup"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `monitor` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var (
@@ -56,8 +54,8 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	)
 	monitorCommand := &cobra.Command{
 		Use:   "monitor",
-		Short: tr("Open a communication port with a board."),
-		Long:  tr("Open a communication port with a board."),
+		Short: i18n.Tr("Open a communication port with a board."),
+		Long:  i18n.Tr("Open a communication port with a board."),
 		Example: "" +
 			"  " + os.Args[0] + " monitor -p /dev/ttyACM0\n" +
 			"  " + os.Args[0] + " monitor -p /dev/ttyACM0 --describe",
@@ -71,11 +69,11 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	}
 	portArgs.AddToCommand(monitorCommand, srv)
 	profileArg.AddToCommand(monitorCommand, srv)
-	monitorCommand.Flags().BoolVar(&raw, "raw", false, tr("Set terminal in raw mode (unbuffered)."))
-	monitorCommand.Flags().BoolVar(&describe, "describe", false, tr("Show all the settings of the communication port."))
-	monitorCommand.Flags().StringSliceVarP(&configs, "config", "c", []string{}, tr("Configure communication port settings. The format is <ID>=<value>[,<ID>=<value>]..."))
-	monitorCommand.Flags().BoolVarP(&quiet, "quiet", "q", false, tr("Run in silent mode, show only monitor input and output."))
-	monitorCommand.Flags().BoolVar(&timestamp, "timestamp", false, tr("Timestamp each incoming line."))
+	monitorCommand.Flags().BoolVar(&raw, "raw", false, i18n.Tr("Set terminal in raw mode (unbuffered)."))
+	monitorCommand.Flags().BoolVar(&describe, "describe", false, i18n.Tr("Show all the settings of the communication port."))
+	monitorCommand.Flags().StringSliceVarP(&configs, "config", "c", []string{}, i18n.Tr("Configure communication port settings. The format is <ID>=<value>[,<ID>=<value>]..."))
+	monitorCommand.Flags().BoolVarP(&quiet, "quiet", "q", false, i18n.Tr("Run in silent mode, show only monitor input and output."))
+	monitorCommand.Flags().BoolVar(&timestamp, "timestamp", false, i18n.Tr("Timestamp each incoming line."))
 	fqbnArg.AddToCommand(monitorCommand, srv)
 	return monitorCommand
 }
@@ -107,7 +105,7 @@ func runMonitorCmd(
 	resp, err := srv.LoadSketch(ctx, &rpc.LoadSketchRequest{SketchPath: sketchPath.String()})
 	if err != nil && !portArgs.IsPortFlagSet() {
 		feedback.Fatal(
-			tr("Error getting default port from `sketch.yaml`. Check if you're in the correct sketch folder or provide the --port flag: %s", err),
+			i18n.Tr("Error getting default port from `sketch.yaml`. Check if you're in the correct sketch folder or provide the --port flag: %s", err),
 			feedback.ErrGeneric,
 		)
 	}
@@ -152,7 +150,7 @@ func runMonitorCmd(
 		Fqbn:         fqbn,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error getting port settings details: %s", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error getting port settings details: %s", err), feedback.ErrGeneric)
 	}
 	if describe {
 		settings := make([]*result.MonitorPortSettingDescriptor, len(enumerateResp.GetSettings()))
@@ -184,7 +182,7 @@ func runMonitorCmd(
 				} else {
 					if strings.EqualFold(s.GetSettingId(), k) {
 						if !contains(s.GetEnumValues(), v) {
-							feedback.Fatal(tr("invalid port configuration value for %s: %s", k, v), feedback.ErrBadArgument)
+							feedback.Fatal(i18n.Tr("invalid port configuration value for %s: %s", k, v), feedback.ErrBadArgument)
 						}
 						setting = s
 						break
@@ -192,14 +190,14 @@ func runMonitorCmd(
 				}
 			}
 			if setting == nil {
-				feedback.Fatal(tr("invalid port configuration: %s", config), feedback.ErrBadArgument)
+				feedback.Fatal(i18n.Tr("invalid port configuration: %s", config), feedback.ErrBadArgument)
 			}
 			configuration.Settings = append(configuration.GetSettings(), &rpc.MonitorPortSetting{
 				SettingId: setting.GetSettingId(),
 				Value:     v,
 			})
 			if !quiet {
-				feedback.Print(tr("Monitor port settings:"))
+				feedback.Print(i18n.Tr("Monitor port settings:"))
 				feedback.Print(fmt.Sprintf("%s=%s", setting.GetSettingId(), v))
 			}
 		}
@@ -218,7 +216,7 @@ func runMonitorCmd(
 	if raw {
 		if feedback.IsInteractive() {
 			if err := feedback.SetRawModeStdin(); err != nil {
-				feedback.Warning(tr("Error setting raw mode: %s", err.Error()))
+				feedback.Warning(i18n.Tr("Error setting raw mode: %s", err.Error()))
 			}
 			defer feedback.RestoreModeStdin()
 		}
@@ -240,7 +238,7 @@ func runMonitorCmd(
 	})
 	go func() {
 		if !quiet {
-			feedback.Print(tr("Connecting to %s. Press CTRL-C to exit.", portAddress))
+			feedback.Print(i18n.Tr("Connecting to %s. Press CTRL-C to exit.", portAddress))
 		}
 		if err := srv.Monitor(monitorServer); err != nil {
 			feedback.FatalError(err, feedback.ErrGeneric)
@@ -252,7 +250,7 @@ func runMonitorCmd(
 		_, err := io.Copy(ttyOut, portProxy)
 		if err != nil && !errors.Is(err, io.EOF) {
 			if !quiet {
-				feedback.Print(tr("Port closed: %v", err))
+				feedback.Print(i18n.Tr("Port closed: %v", err))
 			}
 		}
 		cancel()
@@ -261,7 +259,7 @@ func runMonitorCmd(
 		_, err := io.Copy(portProxy, ttyIn)
 		if err != nil && !errors.Is(err, io.EOF) {
 			if !quiet {
-				feedback.Print(tr("Port closed: %v", err))
+				feedback.Print(i18n.Tr("Port closed: %v", err))
 			}
 		}
 		cancel()
@@ -296,7 +294,7 @@ func (r *detailsResult) String() string {
 		return ""
 	}
 	t := table.New()
-	t.SetHeader(tr("ID"), tr("Setting"), tr("Default"), tr("Values"))
+	t.SetHeader(i18n.Tr("ID"), i18n.Tr("Setting"), i18n.Tr("Default"), i18n.Tr("Values"))
 
 	green := color.New(color.FgGreen)
 	sort.Slice(r.Settings, func(i, j int) bool {
diff --git a/internal/cli/outdated/outdated.go b/internal/cli/outdated/outdated.go
index 7ca0a442e06..ce9b3c87510 100644
--- a/internal/cli/outdated/outdated.go
+++ b/internal/cli/outdated/outdated.go
@@ -34,14 +34,12 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand creates a new `outdated` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	outdatedCommand := &cobra.Command{
 		Use:   "outdated",
-		Short: tr("Lists cores and libraries that can be upgraded"),
-		Long: tr(`This commands shows a list of installed cores and/or libraries
+		Short: i18n.Tr("Lists cores and libraries that can be upgraded"),
+		Long: i18n.Tr(`This commands shows a list of installed cores and/or libraries
 that can be upgraded. If nothing needs to be updated the output is empty.`),
 		Example: "  " + os.Args[0] + " outdated\n",
 		Args:    cobra.NoArgs,
@@ -94,18 +92,18 @@ func (ir outdatedResult) Data() interface{} {
 
 func (ir outdatedResult) String() string {
 	if len(ir.Platforms) == 0 && len(ir.InstalledLibs) == 0 {
-		return tr("No outdated platforms or libraries found.")
+		return i18n.Tr("No outdated platforms or libraries found.")
 	}
 
 	// A table useful both for platforms and libraries, where some of the fields will be blank.
 	t := table.New()
 	t.SetHeader(
-		tr("ID"),
-		tr("Name"),
-		tr("Installed"),
-		tr("Latest"),
-		tr("Location"),
-		tr("Description"),
+		i18n.Tr("ID"),
+		i18n.Tr("Name"),
+		i18n.Tr("Installed"),
+		i18n.Tr("Latest"),
+		i18n.Tr("Location"),
+		i18n.Tr("Description"),
 	)
 	t.SetColumnWidthMode(2, table.Average)
 	t.SetColumnWidthMode(3, table.Average)
@@ -118,7 +116,7 @@ func (ir outdatedResult) String() string {
 			name = latest.Name
 		}
 		if p.Deprecated {
-			name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name)
+			name = fmt.Sprintf("[%s] %s", i18n.Tr("DEPRECATED"), name)
 		}
 		t.AddRow(p.Id, name, p.InstalledVersion, p.LatestVersion, "", "")
 	}
diff --git a/internal/cli/sketch/archive.go b/internal/cli/sketch/archive.go
index 19b2a280651..4c1063bbf5a 100644
--- a/internal/cli/sketch/archive.go
+++ b/internal/cli/sketch/archive.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/arduino/arduino-cli/internal/cli/arguments"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -32,9 +33,9 @@ func initArchiveCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var includeBuildDir, overwrite bool
 
 	archiveCommand := &cobra.Command{
-		Use:   fmt.Sprintf("archive <%s> <%s>", tr("sketchPath"), tr("archivePath")),
-		Short: tr("Creates a zip file containing all sketch files."),
-		Long:  tr("Creates a zip file containing all sketch files."),
+		Use:   fmt.Sprintf("archive <%s> <%s>", i18n.Tr("sketchPath"), i18n.Tr("archivePath")),
+		Short: i18n.Tr("Creates a zip file containing all sketch files."),
+		Long:  i18n.Tr("Creates a zip file containing all sketch files."),
 		Example: "" +
 			"  " + os.Args[0] + " archive\n" +
 			"  " + os.Args[0] + " archive .\n" +
@@ -47,8 +48,8 @@ func initArchiveCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 		},
 	}
 
-	archiveCommand.Flags().BoolVar(&includeBuildDir, "include-build-dir", false, tr("Includes %s directory in the archive.", "build"))
-	archiveCommand.Flags().BoolVarP(&overwrite, "overwrite", "f", false, tr("Overwrites an already existing archive"))
+	archiveCommand.Flags().BoolVar(&includeBuildDir, "include-build-dir", false, i18n.Tr("Includes %s directory in the archive.", "build"))
+	archiveCommand.Flags().BoolVarP(&overwrite, "overwrite", "f", false, i18n.Tr("Overwrites an already existing archive"))
 
 	return archiveCommand
 }
@@ -81,6 +82,6 @@ func runArchiveCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, ar
 			Overwrite:       overwrite,
 		},
 	); err != nil {
-		feedback.Fatal(tr("Error archiving: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error archiving: %v", err), feedback.ErrGeneric)
 	}
 }
diff --git a/internal/cli/sketch/new.go b/internal/cli/sketch/new.go
index 79dfcccc373..024d53e851c 100644
--- a/internal/cli/sketch/new.go
+++ b/internal/cli/sketch/new.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/arduino/arduino-cli/internal/arduino/globals"
 	"github.com/arduino/arduino-cli/internal/cli/feedback"
+	"github.com/arduino/arduino-cli/internal/i18n"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	paths "github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -33,8 +34,8 @@ func initNewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 
 	newCommand := &cobra.Command{
 		Use:     "new",
-		Short:   tr("Create a new Sketch"),
-		Long:    tr("Create a new Sketch"),
+		Short:   i18n.Tr("Create a new Sketch"),
+		Long:    i18n.Tr("Create a new Sketch"),
 		Example: "  " + os.Args[0] + " sketch new MultiBlinker",
 		Args:    cobra.ExactArgs(1),
 		Run: func(cmd *cobra.Command, args []string) {
@@ -42,7 +43,7 @@ func initNewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 		},
 	}
 
-	newCommand.Flags().BoolVarP(&overwrite, "overwrite", "f", false, tr("Overwrites an existing .ino sketch."))
+	newCommand.Flags().BoolVarP(&overwrite, "overwrite", "f", false, i18n.Tr("Overwrites an existing .ino sketch."))
 
 	return newCommand
 }
@@ -67,7 +68,7 @@ func runNewCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
 	} else {
 		sketchDirPath, err = paths.New(trimmedSketchName).Abs()
 		if err != nil {
-			feedback.Fatal(tr("Error creating sketch: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error creating sketch: %v", err), feedback.ErrGeneric)
 		}
 		sketchDir = sketchDirPath.Parent().String()
 		sketchName = sketchDirPath.Base()
@@ -79,7 +80,7 @@ func runNewCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
 		Overwrite:  overwrite,
 	})
 	if err != nil {
-		feedback.Fatal(tr("Error creating sketch: %v", err), feedback.ErrGeneric)
+		feedback.Fatal(i18n.Tr("Error creating sketch: %v", err), feedback.ErrGeneric)
 	}
 
 	feedback.PrintResult(sketchResult{SketchDirPath: sketchDirPath})
@@ -94,5 +95,5 @@ func (ir sketchResult) Data() interface{} {
 }
 
 func (ir sketchResult) String() string {
-	return tr("Sketch created in: %s", ir.SketchDirPath)
+	return i18n.Tr("Sketch created in: %s", ir.SketchDirPath)
 }
diff --git a/internal/cli/sketch/sketch.go b/internal/cli/sketch/sketch.go
index 2530c72247d..65ae9a1838f 100644
--- a/internal/cli/sketch/sketch.go
+++ b/internal/cli/sketch/sketch.go
@@ -23,14 +23,12 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `sketch` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	sketchCommand := &cobra.Command{
 		Use:     "sketch",
-		Short:   tr("Arduino CLI sketch commands."),
-		Long:    tr("Arduino CLI sketch commands."),
+		Short:   i18n.Tr("Arduino CLI sketch commands."),
+		Long:    i18n.Tr("Arduino CLI sketch commands."),
 		Example: "  " + os.Args[0] + " sketch new MySketch",
 	}
 
diff --git a/internal/cli/update/update.go b/internal/cli/update/update.go
index 6fd4e7c91e0..950f347a7b4 100644
--- a/internal/cli/update/update.go
+++ b/internal/cli/update/update.go
@@ -29,22 +29,20 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand creates a new `update` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var showOutdated bool
 	updateCommand := &cobra.Command{
 		Use:     "update",
-		Short:   tr("Updates the index of cores and libraries"),
-		Long:    tr("Updates the index of cores and libraries to the latest versions."),
+		Short:   i18n.Tr("Updates the index of cores and libraries"),
+		Long:    i18n.Tr("Updates the index of cores and libraries to the latest versions."),
 		Example: "  " + os.Args[0] + " update",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
 			runUpdateCommand(cmd.Context(), srv, showOutdated)
 		},
 	}
-	updateCommand.Flags().BoolVar(&showOutdated, "show-outdated", false, tr("Show outdated cores and libraries after index update"))
+	updateCommand.Flags().BoolVar(&showOutdated, "show-outdated", false, i18n.Tr("Show outdated cores and libraries after index update"))
 	return updateCommand
 }
 
diff --git a/internal/cli/updater/updater.go b/internal/cli/updater/updater.go
index 1ebd0d382b1..0ba9498ab11 100644
--- a/internal/cli/updater/updater.go
+++ b/internal/cli/updater/updater.go
@@ -24,12 +24,10 @@ import (
 	"github.com/fatih/color"
 )
 
-var tr = i18n.Tr
-
 // NotifyNewVersionIsAvailable prints information about the new latestVersion
 func NotifyNewVersionIsAvailable(latestVersion string) {
 	msg := fmt.Sprintf("\n\n%s %s → %s\n%s",
-		color.YellowString(tr("A new release of Arduino CLI is available:")),
+		color.YellowString(i18n.Tr("A new release of Arduino CLI is available:")),
 		color.CyanString(version.VersionInfo.VersionString),
 		color.CyanString(latestVersion),
 		color.YellowString("https://arduino.github.io/arduino-cli/latest/installation/#latest-packages"))
diff --git a/internal/cli/upgrade/upgrade.go b/internal/cli/upgrade/upgrade.go
index 4c311201dab..8740add67d1 100644
--- a/internal/cli/upgrade/upgrade.go
+++ b/internal/cli/upgrade/upgrade.go
@@ -29,15 +29,13 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand creates a new `upgrade` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	var postInstallFlags arguments.PrePostScriptsFlags
 	upgradeCommand := &cobra.Command{
 		Use:     "upgrade",
-		Short:   tr("Upgrades installed cores and libraries."),
-		Long:    tr("Upgrades installed cores and libraries to latest version."),
+		Short:   i18n.Tr("Upgrades installed cores and libraries."),
+		Long:    i18n.Tr("Upgrades installed cores and libraries to latest version."),
 		Example: "  " + os.Args[0] + " upgrade",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
diff --git a/internal/cli/upload/upload.go b/internal/cli/upload/upload.go
index 752a1a5ccc4..90ba5bf6d7d 100644
--- a/internal/cli/upload/upload.go
+++ b/internal/cli/upload/upload.go
@@ -53,8 +53,8 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	uploadFields := map[string]string{}
 	uploadCommand := &cobra.Command{
 		Use:   "upload",
-		Short: tr("Upload Arduino sketches."),
-		Long:  tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."),
+		Short: i18n.Tr("Upload Arduino sketches."),
+		Long:  i18n.Tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."),
 		Example: "" +
 			"  " + os.Args[0] + " upload /home/user/Arduino/MySketch -p /dev/ttyACM0 -b arduino:avr:uno\n" +
 			"  " + os.Args[0] + " upload -p 192.168.10.1 -b arduino:avr:uno --upload-field password=abc",
@@ -70,14 +70,14 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	fqbnArg.AddToCommand(uploadCommand, srv)
 	portArgs.AddToCommand(uploadCommand, srv)
 	profileArg.AddToCommand(uploadCommand, srv)
-	uploadCommand.Flags().StringVarP(&importDir, "input-dir", "", "", tr("Directory containing binaries to upload."))
-	uploadCommand.Flags().StringVarP(&importFile, "input-file", "i", "", tr("Binary file to upload."))
-	uploadCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload."))
-	uploadCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Optional, turns on verbose mode."))
+	uploadCommand.Flags().StringVarP(&importDir, "input-dir", "", "", i18n.Tr("Directory containing binaries to upload."))
+	uploadCommand.Flags().StringVarP(&importFile, "input-file", "i", "", i18n.Tr("Binary file to upload."))
+	uploadCommand.Flags().BoolVarP(&verify, "verify", "t", false, i18n.Tr("Verify uploaded binary after the upload."))
+	uploadCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, i18n.Tr("Optional, turns on verbose mode."))
 	programmer.AddToCommand(uploadCommand, srv)
-	uploadCommand.Flags().BoolVar(&dryRun, "dry-run", false, tr("Do not perform the actual upload, just log out actions"))
+	uploadCommand.Flags().BoolVar(&dryRun, "dry-run", false, i18n.Tr("Do not perform the actual upload, just log out actions"))
 	uploadCommand.Flags().MarkHidden("dry-run")
-	arguments.AddKeyValuePFlag(uploadCommand, &uploadFields, "upload-field", "F", nil, tr("Set a value for a field required to upload."))
+	arguments.AddKeyValuePFlag(uploadCommand, &uploadFields, "upload-field", "F", nil, i18n.Tr("Set a value for a field required to upload."))
 	return uploadCommand
 }
 
@@ -93,7 +93,7 @@ func runUploadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 	sketch := resp.GetSketch()
 	if importDir == "" && importFile == "" {
 		if err != nil {
-			feedback.Fatal(tr("Error during Upload: %v", err), feedback.ErrGeneric)
+			feedback.Fatal(i18n.Tr("Error during Upload: %v", err), feedback.ErrGeneric)
 		}
 		feedback.WarnAboutDeprecatedFiles(sketch)
 	}
@@ -122,7 +122,7 @@ func runUploadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 		Protocol: port.GetProtocol(),
 	})
 	if err != nil {
-		msg := tr("Error during Upload: %v", err)
+		msg := i18n.Tr("Error during Upload: %v", err)
 
 		// Check the error type to give the user better feedback on how
 		// to resolve it
@@ -130,7 +130,7 @@ func runUploadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 		if errors.As(err, &platformErr) {
 			split := strings.Split(platformErr.Platform, ":")
 			if len(split) < 2 {
-				panic(tr("Platform ID is not correct"))
+				panic(i18n.Tr("Platform ID is not correct"))
 			}
 
 			msg += "\n"
@@ -140,9 +140,9 @@ func runUploadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 			}); err != nil {
 				msg += err.Error()
 			} else if len(platform.GetSearchOutput()) > 0 {
-				msg += tr("Try running %s", fmt.Sprintf("`%s core install %s`", version.VersionInfo.Application, platformErr.Platform))
+				msg += i18n.Tr("Try running %s", fmt.Sprintf("`%s core install %s`", version.VersionInfo.Application, platformErr.Platform))
 			} else {
-				msg += tr("Platform %s is not found in any known index\nMaybe you need to add a 3rd party URL?", platformErr.Platform)
+				msg += i18n.Tr("Platform %s is not found in any known index\nMaybe you need to add a 3rd party URL?", platformErr.Platform)
 			}
 		}
 		feedback.Fatal(msg, feedback.ErrGeneric)
@@ -156,14 +156,14 @@ func runUploadCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
 				if value, ok := uploadFieldsArgs[field.GetName()]; ok {
 					fields[field.GetName()] = value
 				} else {
-					feedback.Fatal(tr("Missing required upload field: %s", field.GetName()), feedback.ErrBadArgument)
+					feedback.Fatal(i18n.Tr("Missing required upload field: %s", field.GetName()), feedback.ErrBadArgument)
 				}
 			}
 		} else {
 			// Otherwise prompt the user for them
-			feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.GetProtocol()))
+			feedback.Print(i18n.Tr("Uploading to specified board using %s protocol requires the following info:", port.GetProtocol()))
 			if f, err := arguments.AskForUserFields(userFieldRes.GetUserFields()); err != nil {
-				msg := fmt.Sprintf("%s: %s", tr("Error getting user input"), err)
+				msg := fmt.Sprintf("%s: %s", i18n.Tr("Error getting user input"), err)
 				feedback.Fatal(msg, feedback.ErrGeneric)
 			} else {
 				fields = f
@@ -231,5 +231,5 @@ func (r *uploadResult) String() string {
 	if r.UpdatedUploadPort == nil {
 		return ""
 	}
-	return tr("New upload port: %[1]s (%[2]s)", r.UpdatedUploadPort.Address, r.UpdatedUploadPort.Protocol)
+	return i18n.Tr("New upload port: %[1]s (%[2]s)", r.UpdatedUploadPort.Address, r.UpdatedUploadPort.Protocol)
 }
diff --git a/internal/cli/usage.go b/internal/cli/usage.go
index 7b2e7ef113a..31c335569bc 100644
--- a/internal/cli/usage.go
+++ b/internal/cli/usage.go
@@ -15,22 +15,18 @@
 
 package cli
 
-import (
-	"github.com/arduino/arduino-cli/internal/i18n"
-)
-
-var tr = i18n.Tr
+import "github.com/arduino/arduino-cli/internal/i18n"
 
 func getUsageTemplate() string {
 	// Force i18n to generate translation strings
-	_ = tr("Usage:")
-	_ = tr("Aliases:")
-	_ = tr("Examples:")
-	_ = tr("Available Commands:")
-	_ = tr("Flags:")
-	_ = tr("Global Flags:")
-	_ = tr("Additional help topics:")
-	_ = tr("Use %s for more information about a command.")
+	_ = i18n.Tr("Usage:")
+	_ = i18n.Tr("Aliases:")
+	_ = i18n.Tr("Examples:")
+	_ = i18n.Tr("Available Commands:")
+	_ = i18n.Tr("Flags:")
+	_ = i18n.Tr("Global Flags:")
+	_ = i18n.Tr("Additional help topics:")
+	_ = i18n.Tr("Use %s for more information about a command.", "")
 
 	return `{{tr "Usage:"}}{{if .Runnable}}
   {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
diff --git a/internal/cli/version/version.go b/internal/cli/version/version.go
index 8c5d8eec4c1..5748ded3a64 100644
--- a/internal/cli/version/version.go
+++ b/internal/cli/version/version.go
@@ -29,14 +29,12 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var tr = i18n.Tr
-
 // NewCommand created a new `version` command
 func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
 	versionCommand := &cobra.Command{
 		Use:     "version",
-		Short:   tr("Shows version number of Arduino CLI."),
-		Long:    tr("Shows the version number of Arduino CLI which is installed on your system."),
+		Short:   i18n.Tr("Shows version number of Arduino CLI."),
+		Long:    i18n.Tr("Shows the version number of Arduino CLI which is installed on your system."),
 		Example: "  " + os.Args[0] + " version",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
diff --git a/internal/inventory/inventory.go b/internal/inventory/inventory.go
index 3155fb4b9db..4792c692bf8 100644
--- a/internal/inventory/inventory.go
+++ b/internal/inventory/inventory.go
@@ -35,7 +35,6 @@ var (
 	Type = "yaml"
 	// Name is the inventory file Name with Type as extension
 	Name           = "inventory" + "." + Type
-	tr             = i18n.Tr
 	configFilePath string
 )
 
@@ -65,13 +64,13 @@ func Init(configPath string) error {
 func generateInstallationData() error {
 	installationID, err := uuid.NewV4()
 	if err != nil {
-		return fmt.Errorf(tr("generating installation.id: %w"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("generating installation.id"), err)
 	}
 	Store.Set("installation.id", installationID.String())
 
 	installationSecret, err := uuid.NewV4()
 	if err != nil {
-		return fmt.Errorf(tr("generating installation.secret: %w"), err)
+		return fmt.Errorf("%s: %w", i18n.Tr("generating installation.secret"), err)
 	}
 	Store.Set("installation.secret", installationSecret.String())
 	return nil
@@ -90,13 +89,13 @@ func WriteStore() error {
 	// Create config dir if not present,
 	// MkdirAll will retrun no error if the path already exists
 	if err := os.MkdirAll(configPath, os.FileMode(0755)); err != nil {
-		return fmt.Errorf(tr("invalid path creating config dir: %[1]s error: %[2]w"), configPath, err)
+		return fmt.Errorf("%s: %w", i18n.Tr("invalid path creating config dir: %[1]s error", configPath), err)
 	}
 
 	// Create file if not present
 	err := Store.WriteConfigAs(configFilePath)
 	if err != nil {
-		return fmt.Errorf(tr("invalid path writing inventory file: %[1]s error: %[2]w"), configFilePath, err)
+		return fmt.Errorf("%s: %w", i18n.Tr("invalid path writing inventory file: %[1]s error", configFilePath), err)
 	}
 
 	return nil
diff --git a/version/version.go b/version/version.go
index abb0f75cc20..2a493597e12 100644
--- a/version/version.go
+++ b/version/version.go
@@ -53,7 +53,7 @@ func NewInfo(application string) *Info {
 }
 
 func (i *Info) String() string {
-	return tr("%[1]s %[2]s Version: %[3]s Commit: %[4]s Date: %[5]s", i.Application, i.Status, i.VersionString, i.Commit, i.Date)
+	return i18n.Tr("%[1]s %[2]s Version: %[3]s Commit: %[4]s Date: %[5]s", i.Application, i.Status, i.VersionString, i.Commit, i.Date)
 }
 
 // Data implements feedback.Result interface