Angular 12 localized with @angular/localize run in docker with nginx

1.1k views Asked by At

I have set up a project with angular 12 and use localization in it. I can successfully run english version of my site, but when I switch to other locales via button which changes url to be localhost/de server responds with many 404 for different files. When I switch back to en it works good.

Package.json

    {
  "name": "my-frontend",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --configuration=development",
    "build": "ng build --localize",
    "transl": "ng extract-i18n --output-path locale --format=xlf2",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "lint": "ng lint",
    "prepare": "husky install"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~12.0.0",
    "@angular/common": "~12.0.0",
    "@angular/compiler": "~12.0.0",
    "@angular/core": "~12.0.0",
    "@angular/forms": "~12.0.0",
    "@angular/platform-browser": "~12.0.0",
    "@angular/platform-browser-dynamic": "~12.0.0",
    "@angular/router": "~12.0.0",
    "@angular/service-worker": "~12.0.0",
    "@ngrx/effects": "^12.0.0",
    "@ngrx/store": "^12.0.0",
    "@ngrx/store-devtools": "^12.0.0",
    "ramda": "^0.27.1",
    "rxjs": "6.6.0",
    "tslib": "^2.1.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~12.0.0",
    "@angular-eslint/builder": "12.0.0",
    "@angular-eslint/eslint-plugin": "12.0.0",
    "@angular-eslint/eslint-plugin-template": "12.0.0",
    "@angular-eslint/schematics": "12.0.0",
    "@angular-eslint/template-parser": "12.0.0",
    "@angular/cli": "~12.0.0",
    "@angular/compiler-cli": "~12.0.0",
    "@angular/localize": "12.0.0",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^12.11.1",
    "@types/ramda": "^0.27.40",
    "@typescript-eslint/eslint-plugin": "4.23.0",
    "@typescript-eslint/parser": "4.23.0",
    "autoprefixer": "^10.2.5",
    "eslint": "^7.26.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-ngrx": "^1.0.0",
    "eslint-plugin-prettier": "^3.4.0",
    "husky": "^6.0.0",
    "jasmine-core": "~3.7.0",
    "karma": "~6.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "postcss": "^8.2.15",
    "postcss-loader": "^5.3.0",
    "prettier": "^2.3.0",
    "tailwindcss": "^2.1.2",
    "typescript": "~4.2.3"
  }
}

Dockerfile


# stage 1  for building the dist folder.
FROM node:14.17-alpine3.13 as my-front-dev
LABEL author="Victor Orlyk"
WORKDIR /app
COPY package.json package.json
COPY yarn.lock yarn.lock
RUN yarn install
#copy all code
COPY . .
RUN yarn run build
#Stage 2
FROM nginx:alpine
# cashing it is default anyway
VOLUME /var/cache/nginx
COPY --from=my-front-dev /app/dist/my-frontend/ /usr/share/nginx/my-frontend/
COPY ./config/nginx.conf /etc/nginx/conf.d/default.conf
# docker build -t nginx-angular -f dockerfile .
# docker run -p 8080:80 nginx-angular

Docker-compose.yml


# This can be used to run a development version of the Angular and Node containers
# See the readme.md for details on changes that are required in the Angular service
# Run docker-compose build
# Run docker-compose up
# Live long and prosper
version: '3.7'
services:
  nginx:
    container_name: nginx-angular
    image: nginx-angular
    build:
      context: .
      dockerfile: dockerfile
    volumes:
      - ./dist/my-frontend:/usr/share/nginx/html
    ports:
      - "80:80"
#    depends_on:
#      - node
    networks:
      - app-network
#  node:
#    container_name: angular-node-service
#    image: angular-node-service
#    build:
#      context: ./server
#      dockerfile: node.dockerfile
#    environment:
#      - NODE_ENV=development
#    ports:
#      - "3000:3000"
#    networks:
#      - app-network
  # Disabled in case someone is running this on Windows (OK to uncomment if on Mac/Linux)
  # cadvisor:
  #   container_name: cadvisor
  #   image: google/cadvisor
  #   volumes:
  #     - /:/rootfs:ro
  #     - /var/run:/var/run:rw
  #     - /sys:/sys:ro
  #     - /var/lib/docker/:/var/lib/docker:ro
  #   ports:
  #     - "8080:8080"
  #   networks:
  #     - app-network
networks:
  app-network:
    driver: bridge

config/nginx.conf


  types {
    module;
  }
  include /etc/nginx/mime.types;
  # Expires map for caching resources
  map $sent_http_content_type $expires {
    default                    off;
    text/html                  epoch;
    text/css                   max;
    application/javascript     max;
    ~image/                    max;
  }
  # Browser preferred language detection
  map $http_accept_language $accept_language {
    ~*^en en;
    ~*^de de;
    ~*^ua ua;
  }
  server {
      listen       80;
    root         /usr/share/nginx/my-frontend;
    # Set cache expires from the map we defined.
    expires $expires;
    # Security. Don't send nginx version in Server header.
    server_tokens off;
    # Fallback to default language if no preference defined by browser
    if ($accept_language ~ "^$") {
      set $accept_language "en";
    }
    # Redirect "/" to Angular app in browser's preferred language
    rewrite ^/$ /$accept_language permanent;
    # Everything under the Angular app is always redirected to Angular in the correct language
    location ~ ^/(en|de|ua) {
      try_files $uri /$1/index.html?$args;
      # Add security headers from separate file
#       include /etc/nginx/security-headers.conf;
    }
    # Proxy for APIs.
#     location /api {
#       proxy_pass https://api.address.here;
#     }
  }

app.module.ts


import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { ServiceWorkerModule } from "@angular/service-worker";
import { ReactiveFormsModule } from "@angular/forms";
import { HttpClientModule } from "@angular/common/http";
import { StoreModule } from "@ngrx/store";
import { EffectsModule } from "@ngrx/effects";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";
import { environment } from "@environments/environment";
import { AppComponent } from "./app.component";
import { LandingComponent } from "./features/landing/landing.component";
import { NotFoundComponent } from "./features/not-found/not-found.component";
import { CoreModule } from "./core/core.module";
import { AppRoutingModule } from "./app-routing.module";
@NgModule({
    imports: [
        BrowserModule,
        HttpClientModule,
        ReactiveFormsModule,
        ServiceWorkerModule.register("ngsw-worker.js", {
            enabled: environment.production,
            // Register the ServiceWorker as soon as the app is stable
            // or after 30 seconds (whichever comes first).
            registrationStrategy: "registerWhenStable:30000"
        }),
        AppRoutingModule,
        StoreModule.forRoot({}, {}),
        StoreDevtoolsModule.instrument({
            maxAge: 25,
            logOnly: environment.production
        }),
        EffectsModule.forRoot([]),
        CoreModule
    ],
    declarations: [AppComponent, LandingComponent, NotFoundComponent],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule {}

app.component.html


<div class="home">
    <header>
        <ul class="flex">
            <li><a routerLink="/">Home</a></li>
            <li><a routerLink="/auth/sign-in">Sign in</a></li>
            <li><a routerLink="/auth/sign-up">Sign up</a></li>
            <li><a routerLink="/tasks">Tasks</a></li>
            <li><a routerLink="/chats">Chats</a></li>
            <li><a routerLink="/projects">projects</a></li>
            <li>
                <button>logout</button>
            </li>
        </ul>
        <ng-container *ngFor="let language of languageList">
            <a href="/{{language.code}}/">
                <button class="button">{{language.label}}</button>
            </a></ng-container
        >
    </header>
    <div>
        <router-outlet></router-outlet>
    </div>
</div>

Then commands to run the app

docker compose build
docker compose up -d
0

There are 0 answers