question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

i18n: $localize extraction should handle ES5 concatenated strings

See original GitHub issue

🐞 bug report

Affected Package

The issue is caused by package @angular/localize.

Description

I know using $localize in TypeScript is still unofficially supported and undocumented but it works fine for us in most cases except for multi-line strings.

When using the $localize tag function on a multi-line template literal, whitespaces are taken into account in the computation of the message ID.

This results in different IDs for the same string and multiple trans-units in the XLIFF file for the same translation.

In our use case, we need to split long translated strings to keep our code correctly formatted.

I am not sure this is an expected behavior or an issue.

If this is the expected behavior, is there a way to keep using multi-line template literals and ignoring whitespaces to keep the ID unique?

One solution would be to remove whitespaces by formating template literal to start at the beginning of lines. But it breaks code formatting (see title3 in app.component.ts).

🔬 Minimal Reproduction

Minimal reproduction available at: https://github.com/bravier/localize-multi-line

I’ve generated this example using ng new and added @angular/localize using the official documentation.

See app.component.ts where I translate the same string with only one space added in title2 to keep the lines correctly indented.

Build steps:

  • npm install
  • npm run build
  • http-serve dist/localize-multi-line

🌍 Your Environment

Angular Version:


Angular CLI: 9.1.4
Node: 12.16.3
OS: linux x64

Angular: 9.1.4
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, localize, platform-browser
... platform-browser-dynamic, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.4
@angular-devkit/build-angular     0.901.4
@angular-devkit/build-optimizer   0.901.4
@angular-devkit/build-webpack     0.901.4
@angular-devkit/core              9.1.4
@angular-devkit/schematics        9.1.4
@ngtools/webpack                  9.1.4
@schematics/angular               9.1.4
@schematics/update                0.901.4
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:3
  • Comments:23 (15 by maintainers)

github_iconTop GitHub Comments

1reaction
braviercommented, May 6, 2020

Hello Pete, ​ Thanks for your proposal, it would be a perfect compromise 👍 ​ However I tried it and it doesn’t work as is, because at the end of compilation, when ng build tries to replace pre-built English strings with French ones, it seems to expect every element of the node to be StringLiterals:

ERROR: Localized bundle generation failed: Unexpected messageParts for `$localize` (expected an array of strings).

From function unwrapStringLiteralArray: https://github.com/angular/angular/blob/ecffc3557fe1bff9718c01277498e877ca44588d/packages/localize/src/tools/src/source_file_utils.ts#L188-L194

What am I doing wrong? (You can see the code I used in https://github.com/bravier/localize-multi-line/blob/master/src/app/app.component.ts)

1reaction
petebacondarwincommented, May 5, 2020

Sooooo…

The actual syntax of $localize as a function is:

function $localize(messageParts: TemplateStringsArray, ...expressions: readonly any[]): string

So if you really wanted you could do define a function that creates TemplateStringsArray objects:

function _(cooked: string[], raw: string[] = cooked): TemplateStringsArray {
  Object.defineProperty(cooked, 'raw', {value: raw});
  return cooked as any;
}

And then you could do something like:

$localize(_('blah blah' +
           'rest of line 1\n' +
           'line 2 etc'));

And the @angular/localize translation tooling will pick this up OK. (I claim).

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to concatenate localized strings mindfully - Shopify UX
Localization via string externalization. Developers go through a process called string externalization to ensure content can be localized.
Read more >
Internationalization with @angular/localize | Ninja Squad
Angular 9.0 introduced a new i18n package called @angular/localize. Let's see what we can do with it!
Read more >
How can I do string interpolation in JavaScript? - Stack Overflow
I would love to be able to refer to variables inside strings, but in javascript you need to use concatenation (or some other...
Read more >
String internationalization — CKAN 2.9.7 documentation
Internationalization (or i18n) is the process of marking strings for translation, so that the strings can be extracted from the source code and...
Read more >
Table of Contents - Packt
Performing string interpolation with template literals ... Or, we can use array-destructuring to extract the values from the array:.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found