Jeff Hiatt
Jeff Hiatt

Reputation: 81

Angular 11 - won't find manually created locale files

I have an Angular 11 application for which we support 14 languages, including Samoan and Tagalog, with locales sm and tl respectively. Angular doesn't have locale files for these. I've created and partially translated my own files. However during the build process, I get the following error messages:

Locale data for 'sm' cannot be found.  No locale data will be included for this locale.
Locale data for 'tl' cannot be found.  No locale data will be included for this locale.

The angular.json file contains:

...
      "i18n": {
        "sourceLocale": {
          "code": "en",
          "baseHref": "myApp/en/"
        },
        "locales": {
          "de": {
            "translation": "src/i18n/messages.de.xlf",
            "baseHref": "myApp/de/"
          },
          "sm": {
            "translation": "src/i18n/messages.sm.xlf",
            "baseHref": "myApp/sm/"
          },
          "tl": {
            "translation": "src/i18n/messages.tl.xlf",
            "baseHref": "myApp/tl/"
          },
...

To point Angular at the locale files, I've added the following lines near the top of the app.module.ts file. My personalized locales files are located at the path shown in my app (inside the app folder).

import { registerLocaleData } from '@angular/common';
import localeSm from './pb-locales/sm';
import localeTl from './pb-locales/tl';

registerLocaleData(localeSm, 'sm');
registerLocaleData(localeTl, 'tl');

I can't find a single reference on the web regarding this.

UPDATE: I'll just use Pilipino (Filipino), aka 'fil' as a replacement for Tagalog as Angular supports Filipino.

The sm.js file is a copy of the en.js file, with some changes. Angular can't find it:

/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */
(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(null, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define("@angular/common/locales/sm", ["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
    var u = undefined;
    function plural(n) {
        var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0;
        if (v === 0 && (i === 1 || i === 2 || i === 3) ||
            v === 0 && !(i % 10 === 4 || i % 10 === 6 || i % 10 === 9) ||
            !(v === 0) && !(f % 10 === 4 || f % 10 === 6 || f % 10 === 9))
            return 1;
  return 5;
}

exports.default = [
  'sm',
  [['a', 'p'], ['AM', 'PM'], u],
  [['AM', 'PM'], u, u],
  [
    ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
    ['Aso Sa', 'Aso Gafua', 'Aso Lua', 'Aso Lulu', 'Aso Tofi', 'Aso Faralie', 'Aso Tonaʻi'],
    ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
  ],
  u,
  [
    ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    [
      'Ianuari', 'Fepuari', 'Mati', 'Aperila', 'Me', 'Iuni', 'Iulai', 'Auguso', 'Setema',
      'Oketopa', 'Novema', 'Tesema'
    ]
  ],
  [
    ['E', 'P', 'M', 'A', 'M', 'Hun', 'Hul', 'Ago', 'Set', 'Okt', 'Nob', 'Dis'],
    ['Ene', 'Peb', 'Mar', 'Abr', 'May', 'Hun', 'Hul', 'Ago', 'Set', 'Okt', 'Nob', 'Dis'],
    [
      'Enero', 'Pebrero', 'Marso', 'Abril', 'Mayo', 'Hunyo', 'Hulyo', 'Agosto', 'Setyembre',
      'Oktubre', 'Nobyembre', 'Disyembre'
    ]
  ],
  [['B', 'A'], ['BC', 'AD'], ['Before Christ', 'Anno Domini']],
  0,
  [6, 0],
  ['M/d/yy', 'MMM d, y', 'MMMM d, y', 'EEEE, MMMM d, y'],
  ['h:mm a', 'h:mm:ss a', 'h:mm:ss a z', 'h:mm:ss a zzzz'],
  ['{1}, {0}', u, '{1} \'at\' {0}', u],
  ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'],
  ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'],
  'USD',
  '$',
  'US Dollar',
  {},
  'ltr',
  plural
];
});

I've added a GitHub repository that this can be tested from: https://github.com/DrewShirts/angular-samoan

To reproduce the problem, run the script build prod.

Upvotes: 1

Views: 864

Answers (1)

Jeff Hiatt
Jeff Hiatt

Reputation: 81

The following works, but is a hack. I'm still searching for a better solution short of doing a pull request against the angular code. Surely that is not the only long term solution.

I created a bash script to run as part of the build process that copies the sm.js file from inside the project to node_modules/@angular/common/locales/global

cp ./src/app/locales/sm.js ./node_modules/@angular/common/locales/global/

then modify the package.json:

"build": "./pre-build-hack.sh && ng build --configuration production --localize"

Not an elegant solution, but it works. This does work on our CI/CD platform as well.

Thanks to @Eliseo for the direction that pointed us to this solution.

Upvotes: 1

Related Questions