Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i18n support in Angular libraries #17140

Open
1 of 15 tasks
multimike77 opened this issue Mar 3, 2020 · 34 comments
Open
1 of 15 tasks

i18n support in Angular libraries #17140

multimike77 opened this issue Mar 3, 2020 · 34 comments
Labels
devkit/build-angular:i18n devkit/build-angular:library feature: under consideration Feature request for which voting has completed and the request is now under consideration feature Issue that requests a new feature

Comments

@multimike77
Copy link

🐞 Bug report

Command (mark with an x)

  • new
  • build
  • serve
  • test
  • e2e
  • generate
  • add
  • update
  • lint
  • xi18n
  • run
  • config
  • help
  • version
  • doc

Is this a regression?

No. Related functionaliy only available with new i18n capabilities of angular 9.

Description

I want to use ng xi18n command to extract messages for i18n tags which are part of a library project which is part of a monrepo setup created by the cli. According to docs at

https://angular.io/cli/xi18n this is supposed to be possible

ng xi18n <project>
<project> The name of the project to build. Can be an application or a library.

🔬 Minimal Reproduction

  1. create project: ng new lib-i18n
  2. add localize: ng add @angular/localize
  3. generate library: ng g library my-lib
  4. add i18n attribute in my-lib.component.ts
    <p i18n>
      my-lib works!
    </p>
    
  5. run ng xi18n my-lib: Result will be
    An unhandled exception occurred: Project 'my-lib' does not support the 'extract-i18n' target.
    After adding corresponding extract-i18n target in angular.json, error output as below.

I created a minimal demo project which incorporates the scenario describe above. It is located here:
https://github.com/multimike77/lib-i18n-issue

Checkout and run npm install. Then run ng xi18n my-lib and it should produce error as below.

🔥 Exception or Error


An unhandled exception occurred: The "path" argument must be of type string. Received undefined

[error] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at validateString (internal/validators.js:117:11)
    at Object.resolve (path.js:980:7)
    at Object.getCommonConfig (/Users/.../lib-i18n/node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js:390:24)
    at /Users/.../lib-i18n/node_modules/@angular-devkit/build-angular/src/extract-i18n/index.js:91:27
    at generateWebpackConfig (/Users/.../lib-i18n/node_modules/@angular-devkit/build-angular/src/utils/webpack-browser-config.js:62:22)
    at async Object.generateBrowserWebpackConfigFromContext (/Users/.../lib-i18n/node_modules/@angular-devkit/build-angular/src/utils/webpack-browser-config.js:137:20)
    at async execute (/Users/.../lib-i18n/node_modules/@angular-devkit/build-angular/src/extract-i18n/index.js:73:24)

🌍 Your Environment


Angular CLI: 9.0.4
Node: 12.16.1
OS: darwin x64

Angular: 9.0.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.900.4
@angular-devkit/build-angular      0.900.4
@angular-devkit/build-ng-packagr   0.900.4
@angular-devkit/build-optimizer    0.900.4
@angular-devkit/build-webpack      0.900.4
@angular-devkit/core               9.0.4
@angular-devkit/schematics         9.0.4
@ngtools/webpack                   9.0.4
@schematics/angular                9.0.4
@schematics/update                 0.900.4
ng-packagr                         9.0.2
rxjs                               6.5.4
typescript                         3.7.5
webpack                            4.41.2

Anything else relevant?

@alan-agius4 alan-agius4 added area: @angular/cli area: docs Related to the documentation labels Mar 3, 2020
@ngbot ngbot bot added this to the Backlog milestone Mar 3, 2020
@alan-agius4 alan-agius4 added severity1: confusing freq1: low Only reported by a handful of users who observe it rarely labels Mar 3, 2020
@alan-agius4
Copy link
Collaborator

alan-agius4 commented Mar 3, 2020

Hi @multimike77, thanks for reporting this. The docs seems to be incorrect as i18n extraction is only supported at application level.

@multimike77
Copy link
Author

Thanks, I thought already that it could be like this. Then I will adjust my expectations for now.
Are there any plans to support use cases as this one in a future version?

Overall scenrio would be like that:

  • Library provides its own xlf files containing the translations for text used in the library components
  • Consuming applications can use the translations when creating localized builds

From what I understood from the docs around i18n and ivy in Angular 9, i18n tags are extracted when used in an application. But like this, every application which uses the library will need to provide own translations for the texts used in the library components. This is of course not ideal in regards to reusability.

@alan-agius4
Copy link
Collaborator

@clydin would know more about this topic.

But like this, every application which uses the library will need to provide own translations for the texts used in the library components. This is of course not ideal in regards to re usability.

I think there are two sides of this, you can also say that the library author shouldn't be responsible for the translations themselves, but only provide a way to localise the library.

Though I do understand that this feature might be useful in some cases.

@petebacondarwin
Copy link
Contributor

In the next few weeks (hopefully) I will be working on new translation extraction tooling that understands the new $localize calls. Some of the goals will be to support libraries better. Some ideas:

  • ability to filter the generated translation files to only include translations from specified sets of sources (i.e. not libraries).
  • ability to merge more than one translation file together at the point where we localize an application, so that a library author could provide translation if desired

@multimike77
Copy link
Author

I think there are two sides of this, you can also say that the library author shouldn't be responsible for the translations themselves, but only provide a way to localise the library.

Though I do understand that this feature might be useful in some cases.
Yes of course, that's also a valid point. Any solution should ideally support either scenario of already shipping with translations or only providing support for translations.

In our case it's like several shared components and libraries which are used in multiple applications created by different teams throughout the company. The texts and translations for the library components should only be done once and be the same across the applications.

In the next few weeks (hopefully) I will be working on new translation extraction tooling that understands the new $localize calls. Some of the goals will be to support libraries better.

This sounds promising @petebacondarwin !

@meriturva
Copy link

@petebacondarwin just to know about timings, are we going to see library extraction tool for angular 10 or before?

@petebacondarwin
Copy link
Contributor

That's my plan! But it will be tight.

@michaelhunziker
Copy link

In the next few weeks (hopefully) I will be working on new translation extraction tooling that understands the new $localize calls. Some of the goals will be to support libraries better.

@petebacondarwin: Is there a way to track the progress for these features?

@petebacondarwin
Copy link
Contributor

@michaelhunziker - I have not made much progress. You can follow the various PRs that are in flight can be seen at https://github.com/angular/angular/pulls?q=is%3Apr+is%3Aopen+label%3A%22comp%3A+i18n%22+

@sistla001
Copy link

sistla001 commented Oct 6, 2020

@petebacondarwin - is there a way I could use a cmd like localize-translate to do what ng xi18n does? I tried below command, but it still requires -t which is looking for translated files and don't have these files yet. I want to extract i18n attributes in the HTML to messages.xlf. I need to do this in Angular 10.0.3 (localize-extract is not supported). It is okay if just HTML messages get into the messages.xlf file. Please let me know if there is a work around?

node_modules/.bin/localize-translate --root=dist/libs/my-lib --source=bundles/**/* -o projects/libs/my-lib/src/locale/

@petebacondarwin
Copy link
Contributor

@sistla001 - yes. It is called localize-extract. Try something like

tsc -p tsconfig.app.json
node_modules/.bin/localize-extract -s "out-tsc/**/*.js" -f xlf -o message.xlf

@sistla001
Copy link

sistla001 commented Oct 7, 2020

node_modules/.bin/localize-extract -s "out-tsc/**/*.js" -f xlf -o message.xlf

yeah, but localize-extract is not included with cli 10.0.3, is there an equivalent command that I can use in 10.0.3 library project?

@petebacondarwin
Copy link
Contributor

It is available in @angular/localize version 10.1.0. It is independent of the CLI version.

@kostetskyroma
Copy link

@petebacondarwin what is the right way to extract messages from the library in Angular 11.0.0?

"lib": {
      "projectType": "library",
      ...
      "architect": {
         "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "lib:build",
            "outFile": "messages.xlf",
            "outputPath": "libs/lib/src/i18n",
            "format": "xlf",
            "ivy": true
          }
        }
      }
}

and then I've tried command:

ng run lib:extract-i18n

Ivy extraction enabled but application is not Ivy enabled. Extraction may fail.
An unhandled exception occurred: The "path" argument must be of type string. Received undefined

@petebacondarwin
Copy link
Contributor

Extracting library messages via CLI is not yet supported. You could use localize-extract as described above to do it manually, after building the library in ivy mode.

@alan-agius4 alan-agius4 removed area: @angular/cli area: docs Related to the documentation labels May 24, 2021
@ngbot ngbot bot modified the milestone: Backlog May 24, 2021
@alan-agius4 alan-agius4 added feature Issue that requests a new feature and removed freq1: low Only reported by a handful of users who observe it rarely severity1: confusing triage #1 labels May 24, 2021
@angular-robot
Copy link
Contributor

angular-robot bot commented Feb 1, 2022

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

@multimike77
Copy link
Author

It's good to see some movement here with the voting process. Despite having localize-extract as a workaround, it would be great to have some permanent and standardized solution included in the cli tooling.

Localize-extract was working fine for me so far, although sometimes seems to miss to extract some keys. When running the main app, which then includes the xlf file generated for the library, the warnings for missing keys do show up on console.

@meriturva
Copy link

Sadly this feature is required only by ten developers, not enough I guess.
So we still use and maintain our custom script.

@robert-brower-impaq
Copy link

Sadly this feature is required only by ten developers, not enough I guess. So we still use and maintain our custom script.

then at least 11

@angular-robot angular-robot bot added feature: under consideration Feature request for which voting has completed and the request is now under consideration and removed feature: votes required Feature request which is currently still in the voting phase labels Feb 17, 2022
@jllodra
Copy link

jllodra commented Apr 1, 2022

I am on angular 13, and I spent all the morning trying to figure out why the localize-extract was not extracting the i18n texts from the html template files, it was only extracting $localize from the ts files. Finally found that I had to compile the lib in development, Ivy full compilation mode.

Btw, having this bundled in the cli would help.

@Xriuk
Copy link

Xriuk commented Jun 21, 2022

I am on angular 13, and I spent all the morning trying to figure out why the localize-extract was not extracting the i18n texts from the html template files, it was only extracting $localize from the ts files. Finally found that I had to compile the lib in development, Ivy full compilation mode.

Btw, having this bundled in the cli would help.

For anyone else wondering: I had to create another configuration in angular.json > projects > architect > build > configurations like this:

"i18n": {
  "tsConfig": "tsconfig.lib.i18n.json",
  "project": "ng-packagei18n.json"
}

The project was used to specify a different directory (to avoid overriding existing dists), and in the tsConfig the important options are:

"angularCompilerOptions": {
  "ivy": true,
  "compilationMode": "full",
  "skipTemplateCodegen": false
}

Especially the last one, because Angular sets it to true by default for libraries, this was my problem

@sistla001
Copy link

I am on angular 13, and I spent all the morning trying to figure out why the localize-extract was not extracting the i18n texts from the html template files, it was only extracting $localize from the ts files. Finally found that I had to compile the lib in development, Ivy full compilation mode.

Btw, having this bundled in the cli would help.

For anyone else wondering: I had to create another configuration in angular.json > projects > architect > build > configurations like this:


"i18n": {

  "tsConfig": "tsconfig.lib.i18n.json",

  "project": "ng-packagei18n.json"

}

The project was used to specify a different directory (to avoid overriding existing dists), and in the tsConfig the important options are:


"angularCompilerOptions": {

  "ivy": true,

  "compilationMode": "full",

  "skipTemplateCodegen": false

}

Especially the last one, because Angular sets it to true by default for libraries, this was my problem

What about libraries that are needed to be published to registries? It says, they have to have compilationMode=partial, otherwise I get an error that it can't be published.

@Xriuk
Copy link

Xriuk commented Jul 23, 2022

I am on angular 13, and I spent all the morning trying to figure out why the localize-extract was not extracting the i18n texts from the html template files, it was only extracting $localize from the ts files. Finally found that I had to compile the lib in development, Ivy full compilation mode.

Btw, having this bundled in the cli would help.

For anyone else wondering: I had to create another configuration in angular.json > projects > architect > build > configurations like this:


"i18n": {

  "tsConfig": "tsconfig.lib.i18n.json",

  "project": "ng-packagei18n.json"

}

The project was used to specify a different directory (to avoid overriding existing dists), and in the tsConfig the important options are:


"angularCompilerOptions": {

  "ivy": true,

  "compilationMode": "full",

  "skipTemplateCodegen": false

}

Especially the last one, because Angular sets it to true by default for libraries, this was my problem

What about libraries that are needed to be published to registries? It says, they have to have compilationMode=partial, otherwise I get an error that it can't be published.

You use this configuration only to extract translation strings, if you wanna publish your library you recompile it in partial mode with another configuration

@sistla001
Copy link

sistla001 commented Jul 23, 2022

I am on angular 13, and I spent all the morning trying to figure out why the localize-extract was not extracting the i18n texts from the html template files, it was only extracting $localize from the ts files. Finally found that I had to compile the lib in development, Ivy full compilation mode.

Btw, having this bundled in the cli would help.

For anyone else wondering: I had to create another configuration in angular.json > projects > architect > build > configurations like this:


"i18n": {

  "tsConfig": "tsconfig.lib.i18n.json",

  "project": "ng-packagei18n.json"

}

The project was used to specify a different directory (to avoid overriding existing dists), and in the tsConfig the important options are:


"angularCompilerOptions": {

  "ivy": true,

  "compilationMode": "full",

  "skipTemplateCodegen": false

}

Especially the last one, because Angular sets it to true by default for libraries, this was my problem

What about libraries that are needed to be published to registries? It says, they have to have compilationMode=partial, otherwise I get an error that it can't be published.

You use this configuration only to extract translation strings, if you wanna publish your library you recompile it in partial mode with another configuration

Ok, this may work for the libraries we own. But, any ideas on how texts can be extracted from Kendo/3rd party Libraries? here's the command that used to work with Angular 10 and no longer works after upgrading to angular 14.

node_modules/.bin/localize-extract -s node_modules/@progress/**/dist/fesm2015/*.js -f xlf -o src/locale/xlfs/kendo-messages.xlf. Thanks!

Update: looks like ng extract-i18n <project> --format xlf --output-path src/locale is extracting all texts across custom libraries, kendo (3rd parties) and also does the merge. This is exactly what I am looking for. With angular 10, I was using localize-extract multiple times, then xlf-merge to merge the messages, and then use @ngx-i18nsupport/tooling to merge into language files.

Update: ng-extract-i18n-merge is the library that is letting me extract all texts across custom libraries, kendo (3rd parties), and also does the language merge. Hope this will end up in cli one day.
CC; @petebacondarwin

@alan-agius4 alan-agius4 changed the title ng xi18n not working for library i18n support in Angular libraries Dec 21, 2022
@k3v3n
Copy link

k3v3n commented Feb 15, 2023

Wanted to comment for visibility. I'm working on a project that use a monorepo with multiples apps/projects where we want to make use of incremental builds. To do so, our library needs to import '@angular/localize/init'; to make the compiler happy and not get a missing import error.

We don't seems to have any issue with it so far, but would like to understand more about potential issues about it.

Are there any known best practices for libraries translation as this issue seems blocked for a long time now.

@PowerKiKi
Copy link
Contributor

We also use import '@angular/localize/init'; in our library. And we mark strings to be localized with i18n attribute or $localize() function in the library. Then our app will extract all strings, both from the app itself and the library. This has been working well for us for many months now.

@meriturva
Copy link

Here is an old discussion about library (APF format) and i18n: angular/angular#38366 (comment)

Basically, on my teams, we have more than 100 library projects with translations packed inside plus a schematic that just merge strings from libraries used to xlif file produced by the final app. Just a custom way to make it possible to distribute translations near the library. Another approach is the one chosen by Kendo UI, which just has a big library with all strings from all components plus a script that merge strings on xlif.

What we would like to expect is to have

  1. a way to extract only strings from one library (now we have a custom script that splits the whole extraction to make a single group of strings and packs them to the correct library to distribute)
  2. a way to indicate translations into library APF format (maybe package.json)
  3. a way to read translations from the library and merge them to the final xlif app file

I mean, it is something that we do every day with a custom "build pipeline" but I guess a goal is to propose an official approach to cover this need, mainly for small libraries and not-so-big teams.

My two cents.

@PowerKiKi
Copy link
Contributor

a way to read translations from the library and merge them to the final xlif app file

Pretty sure this is solved already, because it turns out that angular.json property projects.my-project.i18n.locales.my-locale can take a string or an array of strings. If you supply multiples paths to xliff files, those will be "merged" when compiling the localized versions of the bundles.

So basically something like that:

{
    "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
    "projects": {
        // ... other things here...
        "my-project": {
            "i18n": {
                "locales": {
                    "en": [
                        "node_modules/my-library/i18n/messages.en.xlf",
                        "client/i18n/messages.en.xlf"
                    ],
                    "es": [
                        "node_modules/my-library/i18n/messages.es.xlf",
                        "client/i18n/messages.es.xlf"
                    ]
                }
            }
        }
    }
}

@meriturva
Copy link

Yes @PowerKiKi locale now supports merging multiple xlif files on angular.json, the main problem is extraction and packing them

Thanks for the tip!

@gzf6
Copy link

gzf6 commented May 31, 2024

I think we can create a new playground app for each library and perform extraction operations there

@meriturva
Copy link

I think we can create a new playground app for each library and perform extraction operations there

I have a project with 180 libraries! I can't follow that approach.

@magioloro
Copy link

Do you think you could add a library paragraph in Angular documentation (https://angular.io/guide/i18n) ?

I have a workspace with one library and one project. I just spend two hours to finally found that I just needed to apply angular/angular#29536 (comment) : add in package.json > projects > my-lib > architect :

        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "angular-i18n:build"
          }
        },

to generate with ng extract-i18n a single messages.xlf file for my app and my library.

Is there any news on that topic?

If I follow your tip and add "extract-i18n" in the architects section of my lib. But I get the following message by now:

Tried to extract from libs with 'projectType' library, which is not supported. The 'extract-i18n' builder can only extract from
applications.

So translating libraries isn't supported at all, although it is allegedly supported? https://v18.angular.dev/cli/extract-i18n

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
devkit/build-angular:i18n devkit/build-angular:library feature: under consideration Feature request for which voting has completed and the request is now under consideration feature Issue that requests a new feature
Projects
None yet
Development

No branches or pull requests