Angular i18n : How to make language change using URL routing /Switcher Buttons? - internationalization

I am building a simple app to learn internationalisation using Angular 11. The tutorial I am following is: https://lokalise.com/blog/angular-i18n/
I followed the tutorial and tried to create an app with 2 configurations - an En (english) one and an Ru (russian). When I run the app with
ng serve --configuration=ru --open
I can see the russian translation
when I use:
ng serve
It shows me the English version of the app.
Both these configurations run in different ports. I tried to create a language switcher to be able to switch between the english and russian version of the app here is the code for that in
app.component.ts & app.component.html
import { Component } from '#angular/core';
import {registerLocaleData} from '#angular/common';
import localeRu from '#angular/common/locales/ru';
registerLocaleData(localeRu, 'ru');
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
company = "Ash B.";
created_by = $localize`Created by ${this.company}`
today: number = Date.now();
localesList = [
{ code: "en-US", label: 'English' },
{ code: "ru", label: 'Русский' }
];
tasksCount = 201;
genderCode = 0;
// tslint:disable-next-line:typedef
male() { this.genderCode = 0; }
// tslint:disable-next-line:typedef
female() { this.genderCode = 1; }
// tslint:disable-next-line:typedef
other() { this.genderCode = 2; }
}
<ul>
<li *ngFor="let locale of localesList">
<a href="/{{locale.code}}/">
{{locale.label}}
</a>
</li>
</ul>
When I click on the buttons it changes the url from
localhost:4200/ru to localhost:4200/en-Us
but the content of the app is not translated. In order to see the translation I must run 2 different versions of the app. How can I make the language switch when I click on the buttons ?

to switch between versions you need to serve the build instead of serving the development configuration, each language will be compiled into a separate bundle, watch your dist folder after you run ng build --localize=true to make sure everything went ok.

Related

Parse iOS Universal Links with Nativescript Angular?

Following the apple documentation and Branch's documentation here, I have set up a working universal link in my Nativescript Angular (iOS) app. But, how do I parse the link when the app opens?
For example, when someone opens the app from the link, I want to have my app read the link so it can go to the correct page of the app.
There is some helpful code in this answer, but I keep getting errors with it. This could be bc the code is written in vanilla JS and I am not translating it into Angular correctly. The use of "_extends" and "routeUrL" both cause errors for me.
And the Nativescript url-handler plugin does not seem to work without further code.
So, after setting up the universal link, and installing the nativescript url-handler plugin, I have entered the following in app.module.ts:
const Application = require("tns-core-modules/application");
import { handleOpenURL, AppURL } from 'nativescript-urlhandler';
declare var NSUserActivityTypeBrowsingWeb
if (Application.ios) {
const MyDelegate = (function (_super) {
_extends(MyDelegate, _super);
function MyDelegate() {
_super.apply(this, arguments);
}
MyDelegate.prototype.applicationContinueUserActivityRestorationHandler = function (application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
this.routeUrl(userActivity.webpageURL);
}
return true;
};
MyDelegate.ObjCProtocols = [UIApplicationDelegate];
return MyDelegate;
})(UIResponder);
Application.ios.delegate = MyDelegate;
}
...
export class AppModule {
ngOnInit(){
handleOpenURL((appURL: AppURL) => {
console.log('Got the following appURL = ' + appURL);
});
}
}
The trouble seems to be mostly with "_extends" and "_super.apply". For example, I get this error:
'NativeScript encountered a fatal error: TypeError: undefined is not an object (evaluating '_extends')
EDIT: Note that the nativescript-urlhandler plugin is no longer being updated. Does anyone know how to parse universal links with Nativescript?
I have figured out a method to get this working:
The general idea is to use the iOS App Delegate method: applicationContinueUserActivityRestorationHandler.
The syntax in the Nativescript documentation on app delegates did not work for me. You can view that documentation here.
This appears to work:
--once you have a universal link set up, following documentation like here, and now you want your app to read ("handle") the details of the link that was tapped to open the app:
EDIT: This code sample puts everything in one spot in app.module.ts. However, most of the time its better to move things out of app.module and into separate services. There is sample code for doing that in the discussion here. So the below has working code, but keep in mind it is better to put this code in a separate service.
app.module.ts
declare var UIResponder, UIApplicationDelegate
if (app.ios) {
app.ios.delegate = UIResponder.extend({
applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
let tappedUniversalLink = userActivity.webpageURL
console.log('the universal link url was = ' + tappedUniversalLink)
}
return true;
}
},
{
name: "CustomAppDelegate",
protocols: [UIApplicationDelegate]
});
}
NOTE: to get the NSUserActivity/Application Delegate stuff to work with typescript, I also needed to download the tns-platforms-declarations plugin, and configure the app. So:
$ npm i tns-platforms-declarations
and
references.d.ts
/// <reference path="./node_modules/tns-platform-declarations/ios.d.ts" />
The above code works for me to be able to read the details of the tapped universal link when the link opens the app.
From there, you can determine what you want to do with that information. For example, if you want to navigate to a specific page of your app depending on the details of the universal link, then I have found this to work:
app.module.ts
import { ios, resumeEvent, on as applicationOn, run as applicationRun, ApplicationEventData } from "tns-core-modules/application";
import { Router } from "#angular/router";
let univeralLinkUrl = ''
let hasLinkBeenTapped = false
if (app.ios) {
//code from above, to get value of the universal link
applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
hasLinkBeenTapped = true
universalLinkUrl = userActivity.webpageURL
}
return true;
},
{
name: "CustomAppDelegate",
protocols: [UIApplicationDelegate]
});
}
#ngModule({...})
export class AppModule {
constructor(private router: Router) {
applicationOn(resumeEvent, (args) => {
if (hasLinkBeenTapped === true){
hasLinkBeenTapped = false //set back to false bc if you don't app will save setting of true, and always assume from here out that the universal link has been tapped whenever the app opens
let pageToOpen = //parse universalLinkUrl to get the details of the page you want to go to
this.router.navigate(["pageToOpen"])
} else {
universalLinkUrl = '' //set back to blank
console.log('app is resuming, but universal Link has not been tapped')
}
})
}
}
You can use the nativescript-plugin-universal-links plugin to do just that.
It has support for dealing with an existing app delegate so if you do have another plugin that implements an app delegate, both of them will work.
Here's the usage example from the docs:
import { Component, OnInit } from "#angular/core";
import { registerUniversalLinkCallback } from "nativescript-plugin-universal-links";
#Component({
selector: "my-app",
template: "<page-router-outlet></page-router-outlet>"
})
export class AppComponent {
constructor() {}
ngOnInit() {
registerUniversalLinkCallback(ul => {
// use the router to navigate to the screen
});
}
}
And the callback will receive a ul (universal link) param that looks like this
{
"href": "https://www.example.com/blog?title=welcome",
"origin": "https://www.example.com",
"pathname": "/blog",
"query": {
"title": "welcome"
}
}
Disclaimer: I'm the author of the plugin.

Getting sass css modules to show up when using enzyme with gatsby

So I'm having issues when I use enzyme to test a component thats using css modules. Or should I say filename.module.scss
Whats happening when I do something like:
const wrapper = shallow(<MyComponent {...data}/>);
console.log('wrapper = ', wrapper.debug());
My debug works and shows my component structure with all my divs in there. The issue is none of my styles are getting added durning running tests. But when I run Gatsby develop the styles are getting added. So just to be clear only in test mode do I not see the styles added to my component!!!
MyComponent.js
import React, { Component } from 'react';
import styles from ‘./MyComponent.module.scss';
class MyComponent extends Component {
render() {
const {
name,
} = this.props;
return (
<React.Fragment>
<div className={styles.header}>
<div className={styles.name}>{name}</div>
</div>
</React.Fragment>
);
}
}
My debug is showing all styles as undefined which is driving me crazy as I can't test based on style name if a div exists.
Here is my package setup for jest.
"jest": {
"moduleNameMapper": {
"\\.(css|scss)$": "<rootDir>/.jest/styleMock.js"
},
"setupFiles": [
"<rootDir>/.jest/setupFiles.js"
]
}
For anyone else running into this issue.
npm install identity-obj-proxy
then add this to your package.json
"jest": {
"moduleNameMapper": {
".+\\.(css|styl|sass|scss)$": "identity-obj-proxy"
},
"setupFiles": [
"<rootDir>/.jest/setupFiles.js"
]
}
Hope this helps someone.

How to fetch the device information using Angular2 and Typescript

I have a table, I need to fill these details into my table from typescript.
1.Device Name
2. Device OS
3. Location
4. Browser
5. IsActive
These fields must be filled from typescript, so can anyone help me to solve this
You can use, ngx-device-detector
ngx-device-detector is An Angular 2 (and beyond) powered AOT
compatible device detector that helps to identify browser, os and
other useful information regarding the device using the app. The
processing is based on user-agent.
Installation:
To install this library, run:
$ npm install ngx-device-detector --save
Usage:
Import DeviceDetectorModule in your app.module.ts
import { NgModule } from '#angular/core';
import { DeviceDetectorModule } from 'ngx-device-detector';
...
#NgModule({
declarations: [
...
LoginComponent,
SignupComponent
...
],
imports: [
CommonModule,
FormsModule,
DeviceDetectorModule.forRoot()
],
providers:[
AuthService
]
...
})
In your component where you want to use the Device Service
import { Component } from '#angular/core';
...
import { DeviceDetectorService } from 'ngx-device-detector';
...
#Component({
selector: 'home', // <home></home>
styleUrls: [ './home.component.scss' ],
templateUrl: './home.component.html',
...
})
export class HomeComponent {
deviceInfo = null;
...
constructor(..., private http: Http, private deviceService: DeviceDetectorService) {
this.epicFunction();
}
...
epicFunction() {
console.log('hello `Home` component');
this.deviceInfo = this.deviceService.getDeviceInfo();
console.log(this.deviceInfo);
}
...
}
Device service:
Holds the following properties:
browser
os
device
userAgent
os_version
You can use angular-device-information is a powerful angular package to detect operating system and version
npm i angular-device-information
import { Component } from '#angular/core';
...
import { AngularDeviceInformationService } from 'angular-device-information';
...
#Component({
selector: 'home', // <home></home>
styleUrls: [ './home.component.scss' ],
templateUrl: './home.component.html',
...
})
export class HomeComponent {
constructor(private deviceInformationService: AngularDeviceInformationService) {
console.log(deviceInformationService.isMobile()); // returns if the device is a mobile device (android / iPhone / windows-phone etc)
console.log(deviceInformationService.isTablet()); // returns if the device is a tablet (tablet iPad etc)
console.log(deviceInformationService.isDesktop()); // returns if the app is running on a Desktop browser.
console.log(deviceInformationService.getDeviceType()); // returns if the app is running on a Desktop browser.
console.log(deviceInformationService.getDeviceInfo().os); // returns os name like Windows/Andtoid/iOS/Linux/Mac OS X etc
console.log(deviceInformationService.getDeviceInfo().osVersion); // returns os version like 10/8.1/7 ...etc
console.log(deviceInformationService.getDeviceInfo().browser); // returns browser name like chrome/firefox ...etc
console.log(deviceInformationService.getDeviceInfo().browserVersion); // returns browser version as number
console.log(deviceInformationService.getDeviceInfo().browserMajorVersion); // returns full browser version as number
console.log(deviceInformationService.getDeviceInfo().screen_resolution); // returns screnn size like 1390x860/640x800 ...etc
console.log(deviceInformationService.getDeviceInfo().cookies); // returns cookies enabled or no
console.log(deviceInformationService.getDeviceInfo().userAgent); // returns userAgent
}
}

JS/(X) import: to import React components?

I want to import a React component from a jsx file in a template and render it in the template with ReactDOM. Later in production I would only want to ship react and all the dependencies of the component only when a site is loaded that has that component.
I have created a React component like this:
editor.jsx
import * as React from "react";
import {Editor} from "draft-js-plugins-editor";
const plugins = [];
export class EditorComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
};
}
onChange(editorState) {
this.setState({
editorState,
});
}
render() {
return (<Editor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={plugins}
/>);
}
}
http://www.phoenixframework.org/docs/static-assets suggests the require syntax for accessing module exports. So I added the following to my template <script>const editor = require("web/static/js/editor").EditorComponent</script>. This does not work though, because the browser cannot interpret require (or brunch does not pick it up).
I configured brunch like so:
plugins: {
babel: {
// Do not use ES6 compiler in vendor code
ignore: [/web\/static\/vendor/],
presets: ["es2015","react"]
}
},
modules: {
autoRequire: {
"js/app.js": ["web/static/js/app"],
"js/editor.jsx": ["web/static/js/editor"]
}
},
I am a bit lost here. How can this be done?
One idea that pops to mind is to create a JS file and import it in the template you want with a <script> tag. In the same template create an empty <div id=editor>. Then, in the JS file import React and ReactDOM and the component you want and use something like this:
ReactDOM.render(
<Editor/>,
document.getElementById("editor")
)
However, I'm not sure I understand your problem correctly.

Loading images in React with Webpack

I'm having trouble getting a simple image to show up in a simple app using Webpack and React.
I've read this thru and tried a few different ways, but keep getting various errors, or at best sometimes no errors, but also no image displaying.
Here is my React component:
import React from 'react';
import styles from '../css/main.css';
import Menu from './Menu';
const logo = require('./images/PIVX_Planet_1a_239x83.png');
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {test: 'foo'};
}
render() {
return (
<div>
<div id='container'></div>
<div className={styles.logo}>
<img src={logo}/>
</div>
<div>
<Menu/>
</div>
</div>
);
}
}
Here is my webpack config:
...
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
"presets": ["react", "es2015", "stage-0", "react-hmre"]
}
}, {
test: /\.(jpg|png|svg)$/,
loader: 'url-loader',
options: {
limit: 25000,
},
}, {
test: /\.json?$/,
loader: 'json'
}, {
test: /\.css$/,
loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]'
}]
}
...
With this, get error from webpack in console:
ERROR in ./app/components/App.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./images/PIVX_Planet_1a_239x83.png in /Users/mac/_DEV/_LAB/PIVX/PIVX-Planet-2/app/components
# ./app/components/App.js 67:11-56
I've also tried using babel-plugin-transform-react-jsx-img-import
(https://www.npmjs.com/package/babel-plugin-transform-react-jsx-img-import)
And then just use:
<div className={styles.logo}>
<img src="./images/PIVX_Planet_1a_239x83.png"/>
</div>
In that case, there are no errors, but the image show up broken.
I've tried changing the relative path to the image with all these combinations.
Directory structure:
app
components
App.js
images
PIVX_Planet_1a_239x83.png
index.html
...
Any insights?
As per your directory structure the path that you need to use is
const logo = require('../images/PIVX_Planet_1a_239x83.png');
since images is under app directory and not under components from where you are trying to get the image location
Also make sure all your loaders are properly installed
you can also try let as:
let logo = require('../images/PIVX_Planet_1a_239x83.png');
Always use let as much as possible to avoid the scope monster
The problem I was having was using
import logo from './images/PIVX_Planet_1a_239x83.png'
instead of
const logo = require('./images/PIVX_Planet_1a_239x83.png');
in a typescript react app w/ a bespoke webpack config.
I have tried everything that you guys have suggested but nothing is working for me. when I put my code in and 'run dev' it come out with an error placeholder. I am using it in the app.js and would like my logo as a link to the home page or just show up at all, in this case I was attempting to just have it on the page.
import '../styles/globals.css'
import Link from 'next/link'
import bpdlogofull from '../public/bpdlogofull.png'
`function MyApp({ Component, pageProps }) {
return (
<div>
<nav className="border-b p-6">
<img src={bpdlogofull} alt='logo'className='flex justify-end'/>
<div className="flex mt-4">
<Link href="/" className="home-button">

Resources