You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by ha...@apache.org on 2021/10/11 07:56:15 UTC

[incubator-hop] branch master updated: HOP-3377 Add transformation to standardize the phone numbers

This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hop.git


The following commit(s) were added to refs/heads/master by this push:
     new cfed696  HOP-3377 Add transformation to standardize the phone numbers
     new 08d0621  Merge pull request #1128 from nadment/HOP-3377
cfed696 is described below

commit cfed696cddf7949f0badabcaa50997bb79077c08
Author: Nicolas Adment <na...@gmail.com>
AuthorDate: Sun Oct 10 17:56:31 2021 +0200

    HOP-3377 Add transformation to standardize the phone numbers
---
 assemblies/plugins/dist/pom.xml                    |  13 +
 assemblies/plugins/transforms/pom.xml              |   1 +
 .../transforms/standardizephonenumber/pom.xml      |  46 ++++
 .../src/assembly/assembly.xml                      |  49 ++++
 .../src/main/resources/version.xml                 |  20 ++
 .../modules/ROOT/pages/pipeline/transforms.adoc    |   1 +
 .../transforms/standardizephonenumber.adoc         |  47 ++++
 plugins/transforms/pom.xml                         |   1 +
 plugins/transforms/standardizephonenumber/pom.xml  |  46 ++++
 .../StandardizePhoneField.java                     | 150 +++++++++++
 .../StandardizePhoneNumber.java                    | 216 +++++++++++++++
 .../StandardizePhoneNumberData.java                |  31 +++
 .../StandardizePhoneNumberDialog.java              | 292 +++++++++++++++++++++
 .../StandardizePhoneNumberMeta.java                | 232 ++++++++++++++++
 .../messages/messages_en_US.properties             |  59 +++++
 .../src/main/resources/standardizephonenumber.svg  |  34 +++
 .../samples/transforms/standardizephonenumber.hpl  | 198 ++++++++++++++
 .../StandardizePhoneNumberMetaInjectionTest.java   |  44 ++++
 .../StandardizePhoneNumberMetaTest.java            |  58 ++++
 19 files changed, 1538 insertions(+)

diff --git a/assemblies/plugins/dist/pom.xml b/assemblies/plugins/dist/pom.xml
index 3e6b543..69d58ee 100644
--- a/assemblies/plugins/dist/pom.xml
+++ b/assemblies/plugins/dist/pom.xml
@@ -2158,6 +2158,19 @@
 
     <dependency>
       <groupId>org.apache.hop</groupId>
+      <artifactId>hop-assemblies-plugins-transforms-standardizephonenumber</artifactId>
+      <version>${hop-plugins-transforms.version}</version>
+      <type>zip</type>
+      <exclusions>
+        <exclusion>
+          <groupId>*</groupId>
+          <artifactId>*</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.hop</groupId>
       <artifactId>hop-assemblies-plugins-transforms-streamlookup</artifactId>
       <version>${hop-plugins-transforms.version}</version>
       <type>zip</type>
diff --git a/assemblies/plugins/transforms/pom.xml b/assemblies/plugins/transforms/pom.xml
index 2c303c1..3469a73 100644
--- a/assemblies/plugins/transforms/pom.xml
+++ b/assemblies/plugins/transforms/pom.xml
@@ -139,6 +139,7 @@
     <module>sql</module>
     <module>sqlfileoutput</module>
     <module>ssh</module>
+    <module>standardizephonenumber</module>
     <module>streamlookup</module>
     <module>streamschemamerge</module>
     <module>stringcut</module>
diff --git a/assemblies/plugins/transforms/standardizephonenumber/pom.xml b/assemblies/plugins/transforms/standardizephonenumber/pom.xml
new file mode 100644
index 0000000..0fb3f7b
--- /dev/null
+++ b/assemblies/plugins/transforms/standardizephonenumber/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.hop</groupId>
+        <artifactId>hop-assemblies-plugins-transforms</artifactId>
+        <version>1.1.0-SNAPSHOT</version>
+    </parent>
+
+
+    <artifactId>hop-assemblies-plugins-transforms-standardizephonenumber</artifactId>
+    <version>1.1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>Hop Assemblies Plugins Transforms Standardize Phone Number</name>
+    <description></description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.hop</groupId>
+            <artifactId>hop-transform-standardizephonenumber</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/assemblies/plugins/transforms/standardizephonenumber/src/assembly/assembly.xml b/assemblies/plugins/transforms/standardizephonenumber/src/assembly/assembly.xml
new file mode 100644
index 0000000..9d3f113
--- /dev/null
+++ b/assemblies/plugins/transforms/standardizephonenumber/src/assembly/assembly.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+    <id>hop-assemblies-plugins-transforms-standardizephonenumber</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <baseDirectory>transforms/standardizephonenumber</baseDirectory>
+    <files>
+        <file>
+            <source>${project.basedir}/src/main/resources/version.xml</source>
+            <outputDirectory>.</outputDirectory>
+            <filtered>true</filtered>
+        </file>
+    </files>
+    <dependencySets>
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <includes>
+                <include>org.apache.hop:hop-transform-standardizephonenumber:jar</include>
+            </includes>
+        </dependencySet>
+				<dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>lib</outputDirectory>
+            <includes>
+                <include>com.googlecode.libphonenumber:libphonenumber:jar</include>
+            </includes>
+        </dependencySet>    
+    </dependencySets>
+</assembly>
\ No newline at end of file
diff --git a/assemblies/plugins/transforms/standardizephonenumber/src/main/resources/version.xml b/assemblies/plugins/transforms/standardizephonenumber/src/main/resources/version.xml
new file mode 100644
index 0000000..6be576a
--- /dev/null
+++ b/assemblies/plugins/transforms/standardizephonenumber/src/main/resources/version.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<version>${project.version}</version>
\ No newline at end of file
diff --git a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc
index 310e126..994366d 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc
@@ -176,6 +176,7 @@ The pages nested under this topic contain information on how to use the transfor
 * xref:pipeline/transforms/splitfieldtorows.adoc[Split fields to rows]
 * xref:pipeline/transforms/splunkinput.adoc[Splunk Input]
 * xref:pipeline/transforms/sqlfileoutput.adoc[SQL File Output]
+* xref:pipeline/transforms/standardizephonenumber.adoc[Standardize Phone Number]
 * xref:pipeline/transforms/streamlookup.adoc[Stream Lookup]
 * xref:pipeline/transforms/streamschemamerge.adoc[Stream Schema Merge]
 * xref:pipeline/transforms/stringcut.adoc[String cut]
diff --git a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/standardizephonenumber.adoc b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/standardizephonenumber.adoc
new file mode 100644
index 0000000..b61ff2f
--- /dev/null
+++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/standardizephonenumber.adoc
@@ -0,0 +1,47 @@
+////
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+////
+:documentationPath: /pipeline/transforms/
+:language: en_US
+
+= Standardize Phone Number
+
+== Description
+
+This transform normalize phone number in a standardized and consistent manner using Google libphonenumber library.
+
+
+
+== Options
+
+[width="90%",options="header"]
+|===
+|Option|Description
+|Transform name|Name of the transform.
+|Input field|The field holding the phone numbers from the input data.
+|Output field|Leave this field empty if you want to update the input field in stream. Otherwise a new field (string) will be added to the output data.
+|Country field|The field holding the country code from the input data. The country code is required to be in the ISO alpha-2.
+|DefaultCountry|The default country code to use if input data from country field is empty or invalid
+|Format|The format to be used to standardize the phone numbers. The available options are:
+* E164 (default)
+* INTERNATIONAL
+* NATIONAL
+* RFC3966
+|Number type|The result field indicates the type of a processed phone number, such as fixed line, mobile...
+|Is valid|The result field indicates whether a phone number is supposed to be valid
+|===
+
+TIP: If the original phone number already has an international area code, this transform will not normalize it to another country even if the international area code is different from the country input’s international area code.
\ No newline at end of file
diff --git a/plugins/transforms/pom.xml b/plugins/transforms/pom.xml
index 055aba1..5d9159a 100644
--- a/plugins/transforms/pom.xml
+++ b/plugins/transforms/pom.xml
@@ -173,6 +173,7 @@
                 <module>sql</module>
                 <module>sqlfileoutput</module>
                 <module>ssh</module>
+                <module>standardizephonenumber</module>
                 <module>streamlookup</module>
                 <module>streamschemamerge</module>
                 <module>stringcut</module>
diff --git a/plugins/transforms/standardizephonenumber/pom.xml b/plugins/transforms/standardizephonenumber/pom.xml
new file mode 100644
index 0000000..78e3d93
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<project
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.hop</groupId>
+		<artifactId>hop-plugins-transforms</artifactId>
+		<version>1.1.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>hop-transform-standardizephonenumber</artifactId>
+	<packaging>jar</packaging>
+
+	<name>Hop Plugins Transforms Standardize Phone Number</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>com.googlecode.libphonenumber</groupId>
+			<artifactId>libphonenumber</artifactId>
+			<version>8.12.33</version>
+			<scope>compile</scope>
+		</dependency>
+	</dependencies>
+
+</project>
\ No newline at end of file
diff --git a/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneField.java b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneField.java
new file mode 100644
index 0000000..a8c67ce
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneField.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hop.metadata.api.HopMetadataProperty;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+
+/**
+ * Contains the properties of the fields to standardize.
+ */
+public class StandardizePhoneField implements Cloneable {
+
+  /** The input field name */
+  @HopMetadataProperty(key = "input",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.InputField")
+  private String inputField = null;
+
+  /** The target field name */
+  @HopMetadataProperty(key = "output",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.OutputField")
+  private String outputField = null;
+
+  /** The format */
+  @HopMetadataProperty(key = "format",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.NumberFormat")
+  private String numberFormat = PhoneNumberFormat.E164.name();
+  
+  /** The country field name */
+  @HopMetadataProperty(key = "country",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.CountryField")
+  private String countryField = null;
+
+  @HopMetadataProperty(key = "defaultCountry",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.DefaultCountry")
+  private String defaultCountry;
+
+  @HopMetadataProperty(key = "numbertype",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.NumberTypeField")
+  private String numberTypeField;
+
+  @HopMetadataProperty(key = "isvalidnumber",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.IsValidNumberField")
+  private String isValidNumberField = null;
+
+
+  public StandardizePhoneField() {
+    super();
+  }
+
+  public StandardizePhoneField(StandardizePhoneField other) {
+    super();
+    
+    this.inputField = other.inputField;
+    this.outputField = other.outputField;
+    this.numberFormat = other.numberFormat;
+    this.countryField = other.countryField;
+    this.defaultCountry = other.defaultCountry;
+    this.numberTypeField = other.numberTypeField;
+    this.defaultCountry = other.defaultCountry;
+    this.isValidNumberField = other.isValidNumberField;
+  }
+  
+  @Override
+  public Object clone() {
+    return new StandardizePhoneField(this);  
+  }
+
+  public String getInputField() {
+    return inputField;
+  }
+
+  public void setInputField(final String field) {
+    this.inputField = StringUtils.stripToNull(field);
+  }
+
+  public String getOutputField() {
+    return outputField;
+  }
+
+  public void setOutputField(final String field) {
+    this.outputField = StringUtils.stripToNull(field);
+  }
+
+  public String getCountryField() {
+    return countryField;
+  }
+
+  public void setCountryField(final String field) {
+    this.countryField = StringUtils.stripToNull(field);
+  }
+
+
+  /**
+   * Get the country codes (ISO 2)
+   * 
+   * @return
+   */
+  public String getDefaultCountry() {
+    return defaultCountry;
+  }
+
+  /**
+   * Set the country codes (ISO 2)
+   * 
+   * @param country
+   */
+  public void setDefaultCountry(String country) {
+    this.defaultCountry = country;
+  }
+  
+  public String getNumberFormat() {
+    return numberFormat;
+  }
+
+  public void setNumberFormat(final String param) {
+      this.numberFormat = param;
+  }
+
+  public String getNumberTypeField() {
+    return numberTypeField;
+  }
+
+  public void setNumberTypeField(final String phoneNumberTypeField) {
+    this.numberTypeField = StringUtils.stripToNull(phoneNumberTypeField);
+  }
+
+  public String getIsValidNumberField() {
+    return isValidNumberField;
+  }
+
+  public void setIsValidNumberField(final String field) {
+    this.isValidNumberField = StringUtils.stripToNull(field);
+  }
+}
diff --git a/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumber.java b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumber.java
new file mode 100644
index 0000000..2daeecc
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumber.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.util.Utils;
+import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.pipeline.Pipeline;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.transform.BaseTransform;
+import org.apache.hop.pipeline.transform.ITransform;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import java.util.Arrays;
+import java.util.Set;
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
+
+public class StandardizePhoneNumber extends BaseTransform<StandardizePhoneNumberMeta, StandardizePhoneNumberData>
+    implements ITransform<StandardizePhoneNumberMeta, StandardizePhoneNumberData> {
+  private static final Class<?> PKG = StandardizePhoneNumber.class; // For Translator
+
+  private PhoneNumberUtil phoneNumberService;
+  private Set<String> supportedRegions;
+  
+  public StandardizePhoneNumber(
+      TransformMeta transformMeta,
+      StandardizePhoneNumberMeta meta,
+      StandardizePhoneNumberData data,
+      int copyNr,
+      PipelineMeta pipelineMeta,
+      Pipeline pipeline) {
+    super(transformMeta, meta, data, copyNr, pipelineMeta, pipeline);
+  }
+
+
+  @Override
+  public boolean processRow() throws HopException {
+
+    // get incoming row, getRow() potentially blocks waiting for more rows,
+    // returns null if no more rows expected
+    Object[] row = getRow();
+
+    // if no more rows are expected, indicate step is finished and
+    // processRow() should not be called again
+    if (row == null) {
+        setOutputDone();
+        return false;
+    }
+
+    // the "first" flag is inherited from the base step implementation
+    // it is used to guard some processing tasks, like figuring out field
+    // indexes
+    // in the row structure that only need to be done once
+    if (first) {
+        if (log.isDebug()) {
+            logDebug(BaseMessages.getString(PKG, "StandardizePhoneNumber.Log.StartedProcessing"));
+        }
+
+        first = false;
+        // clone the input row structure and place it in our data object
+        data.outputRowMeta = getInputRowMeta().clone();
+        // use meta.getFields() to change it, so it reflects the output row
+        // structure
+        meta.getFields(data.outputRowMeta, this.getTransformName(), null, null, this, null);
+    }
+
+    IRowMeta inputRowMeta = getInputRowMeta();
+
+    // copies row into outputRowValues and pads extra null-default slots for
+    // the output values
+    Object[] outputRow = Arrays.copyOf(row, data.outputRowMeta.size());
+
+    for (StandardizePhoneField standardize : meta.getFields()) {
+
+        // Default region
+        String region = standardize.getDefaultCountry();
+        if (!Utils.isEmpty(standardize.getCountryField())) {
+
+            int index = inputRowMeta.indexOfValue(standardize.getCountryField());
+
+            // if country field not found
+            if (index < 0) {
+                logError(BaseMessages.getString(PKG, "StandardizePhoneNumber.Log.CountryFieldNotFound",
+                        standardize.getCountryField()));
+                this.setErrors(1);
+                return false;
+            }
+
+            String country = inputRowMeta.getString(row, index);
+            if (country == null || Utils.isEmpty(country)) {
+                region = standardize.getDefaultCountry();                   
+            } else if (supportedRegions.contains(country.toUpperCase())) {
+                region = country.toUpperCase();
+            } else {
+                logError(BaseMessages.getString(PKG, "StandardizePhoneNumber.Log.RegionNotSupported", country));
+                region = standardize.getDefaultCountry();
+            }
+
+        }
+
+        // Parse phone number
+        String value = null;
+        int index = inputRowMeta.indexOfValue(standardize.getInputField());
+
+        // if input field not found
+        if (index < 0) {
+            this.logError(BaseMessages.getString(PKG, "StandardizePhoneNumber.Log.InputFieldNotFound",
+                    standardize.getInputField()));
+            this.setErrors(1);
+            return false;
+        }
+        value = inputRowMeta.getString(row, index);
+
+        if (value != null && !Utils.isEmpty(value)) {
+            PhoneNumber phoneNumber = null;
+            try {
+                // Replace unsupported character wit blank
+                value = value.replace(',', ' ');
+                
+                // Format 
+                PhoneNumberFormat format = getPhoneNumberFormat(standardize.getNumberFormat());
+                
+                // Parse phone number
+                phoneNumber = phoneNumberService.parse(value, region);
+                if (!Utils.isEmpty(standardize.getOutputField())) {
+                    index = data.outputRowMeta.indexOfValue(standardize.getOutputField());
+                }
+                outputRow[index] = phoneNumberService.format(phoneNumber, format);
+            } catch (NumberParseException e) {
+                if (log.isRowLevel()) {
+                    logRowlevel(BaseMessages.getString(PKG, "StandardizePhoneNumber.Log.ProcessPhoneNumberError",
+                            standardize.getInputField(), value));
+                }
+            }
+
+            if (!Utils.isEmpty(standardize.getNumberTypeField())) {
+                int i = data.outputRowMeta.indexOfValue(standardize.getNumberTypeField());
+                if (phoneNumber != null)
+                    outputRow[i] = phoneNumberService.getNumberType(phoneNumber);
+                else
+                    outputRow[i] = "ERROR";
+            }
+
+            if (!Utils.isEmpty(standardize.getIsValidNumberField())) {
+                int i = data.outputRowMeta.indexOfValue(standardize.getIsValidNumberField());
+                if (phoneNumber != null)
+                    outputRow[i] = phoneNumberService.isValidNumber(phoneNumber);
+                else
+                    outputRow[i] = false;
+            }
+        } else {
+            if (!Utils.isEmpty(standardize.getIsValidNumberField())) {
+                int i = data.outputRowMeta.indexOfValue(standardize.getIsValidNumberField());
+                outputRow[i] = false;
+            }
+        }
+    }
+
+    // put the row to the output row stream
+    putRow(data.outputRowMeta, outputRow);
+
+    if (log.isRowLevel()) {
+        logRowlevel(
+                BaseMessages.getString(PKG, "StandardizePhoneNumber.Log.WroteRowToNextTransform", outputRow));
+    }
+
+    // log progress if it is time to to so
+    if (checkFeedback(getLinesRead())) {
+        logBasic("Line nr " + getLinesRead());
+    }
+
+    // indicate that processRow() should be called again
+    return true;
+  }
+
+
+  @Override
+  public boolean init() {
+
+    if (super.init()) {
+      this.phoneNumberService = PhoneNumberUtil.getInstance();
+      this.supportedRegions = phoneNumberService.getSupportedRegions();      
+      return true;
+    }
+
+    return false;
+  }
+
+  public PhoneNumberFormat getPhoneNumberFormat(String value) {
+    try {
+      return PhoneNumberFormat.valueOf(value);
+    } catch (Exception e) {
+      this.logError("Error parsing phone number format", e);
+      return PhoneNumberFormat.E164;
+    }
+  }
+}
diff --git a/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberData.java b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberData.java
new file mode 100644
index 0000000..83e97d3
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberData.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.pipeline.transform.BaseTransformData;
+import org.apache.hop.pipeline.transform.ITransformData;
+
+public class StandardizePhoneNumberData extends BaseTransformData implements ITransformData {
+
+  protected IRowMeta outputRowMeta;
+  
+  public StandardizePhoneNumberData() {
+    super();
+  }
+}
diff --git a/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberDialog.java b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberDialog.java
new file mode 100644
index 0000000..fbd1988
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberDialog.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.util.Utils;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.transform.BaseTransformMeta;
+import org.apache.hop.pipeline.transform.ITransformDialog;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.ui.core.FormDataBuilder;
+import org.apache.hop.ui.core.dialog.BaseDialog;
+import org.apache.hop.ui.core.gui.GuiResource;
+import org.apache.hop.ui.core.widget.ColumnInfo;
+import org.apache.hop.ui.core.widget.ColumnsResizer;
+import org.apache.hop.ui.core.widget.TableView;
+import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import java.util.ArrayList;
+import java.util.List;
+
+public class StandardizePhoneNumberDialog extends BaseTransformDialog implements ITransformDialog {
+
+  private static final Class<?> PKG = StandardizePhoneNumberMeta.class; // for i18n
+  private final StandardizePhoneNumberMeta input; // purposes
+  private TableView wFields;
+
+  public StandardizePhoneNumberDialog(Shell parent, IVariables variables, Object in,
+      PipelineMeta pipelineMeta, String sname) {
+    super(parent, variables, (BaseTransformMeta) in, pipelineMeta, sname);
+    input = (StandardizePhoneNumberMeta) in;    
+  }
+
+  protected void getData() {
+
+    // Fields
+    List<StandardizePhoneField> standardizes = input.getFields();
+    if (standardizes.size() > 0) {
+      Table table = wFields.getTable();
+      // table.removeAll();
+      for (int i = 0; i < standardizes.size(); i++) {
+        StandardizePhoneField standardize = standardizes.get(i);
+        TableItem item = new TableItem(table, SWT.NONE);
+        item.setText(1, StringUtils.stripToEmpty(standardize.getInputField()));
+        item.setText(2, StringUtils.stripToEmpty(standardize.getOutputField()));
+        item.setText(3, StringUtils.stripToEmpty(standardize.getCountryField()));
+        item.setText(4, StringUtils.stripToEmpty(standardize.getDefaultCountry()));       
+        item.setText(5, StringUtils.stripToEmpty(standardize.getNumberFormat()));
+        item.setText(6, StringUtils.stripToEmpty(standardize.getNumberTypeField()));
+        item.setText(7, StringUtils.stripToEmpty(standardize.getIsValidNumberField()));
+      }
+    }
+
+    wFields.removeEmptyRows();
+    wFields.setRowNums();
+    wFields.optWidth(true);
+
+    wTransformName.selectAll();
+    wTransformName.setFocus();
+  }
+
+  @Override
+  public String open() {
+    Shell parent = getParent();
+
+    shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN);
+    shell.setText(BaseMessages.getString(PKG, "StandardizePhoneNumberDialog.Shell.Title"));
+    shell.setMinimumSize(650, 350);
+    props.setLook(shell);
+    setShellImage(shell, input);
+
+    FormLayout formLayout = new FormLayout();
+    formLayout.marginWidth = Const.FORM_MARGIN;
+    formLayout.marginHeight = Const.FORM_MARGIN;
+    shell.setLayout(formLayout);
+    
+    int margin = props.getMargin();
+
+    // The buttons at the bottom of the dialog
+    //
+    wOk = new Button(shell, SWT.PUSH);
+    wOk.setText(BaseMessages.getString(PKG, "System.Button.OK"));
+    wOk.addListener(SWT.Selection, e -> ok());
+
+    wCancel = new Button(shell, SWT.PUSH);
+    wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel"));
+    wCancel.addListener(SWT.Selection, e -> cancel());
+
+    setButtonPositions(new Button[] {wOk, wCancel}, margin, null);
+    
+    Label hSpacer = new Label(shell, SWT.HORIZONTAL | SWT.SEPARATOR);  
+    hSpacer.setLayoutData(new FormDataBuilder().left().right().bottom(wOk, -margin).height(2).result());
+    
+    // Transform name line
+    //
+    Label wlTransformName = new Label(shell, SWT.RIGHT);
+    wlTransformName.setText(BaseMessages.getString(PKG, "System.Label.TransformName"));
+    wlTransformName.setLayoutData(new FormDataBuilder().left().top().result());
+    props.setLook(wlTransformName);
+
+    wTransformName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
+    wTransformName.setText(transformName);
+    wTransformName.addListener(SWT.Modify, e -> input.setChanged());
+    wTransformName.setLayoutData(
+        new FormDataBuilder().left().top(wlTransformName, margin).right(100, 0).result());
+    props.setLook(wTransformName);    
+    
+    // Table with fields
+    Label lblFields = new Label(shell, SWT.LEFT);
+    lblFields.setText(BaseMessages.getString(PKG, "StandardizePhoneNumberDialog.Fields.Label"));
+    lblFields.setLayoutData(
+        new FormDataBuilder().top(wTransformName, margin).fullWidth().result());
+    props.setLook(lblFields);
+
+    ColumnInfo[] columns =
+        new ColumnInfo[] {
+            new ColumnInfo(
+                BaseMessages.getString(PKG,
+                    "StandardizePhoneNumberDialog.ColumnInfo.InputField.Label"),
+                ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] {""}, false),
+            new ColumnInfo(
+                BaseMessages.getString(PKG,
+                    "StandardizePhoneNumberDialog.ColumnInfo.OutputField.Label"),
+                ColumnInfo.COLUMN_TYPE_TEXT, new String[] {""}, false),
+            new ColumnInfo(
+                BaseMessages.getString(PKG,
+                    "StandardizePhoneNumberDialog.ColumnInfo.CountryField.Label"),
+                ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] {""}, false),
+            new ColumnInfo(
+                BaseMessages.getString(PKG,
+                    "StandardizePhoneNumberDialog.ColumnInfo.DefaultCountry.Label"),
+                ColumnInfo.COLUMN_TYPE_CCOMBO, input.getSupportedCountries(), false),            
+            new ColumnInfo(
+                BaseMessages.getString(PKG, "StandardizePhoneNumberDialog.ColumnInfo.NumberFormat.Label"),
+                ColumnInfo.COLUMN_TYPE_CCOMBO, input.getSupportedFormats(), false),
+            new ColumnInfo(
+                BaseMessages.getString(PKG,
+                    "StandardizePhoneNumberDialog.ColumnInfo.NumberTypeField.Label"),
+                ColumnInfo.COLUMN_TYPE_TEXT, new String[] {""}, false),
+            new ColumnInfo(
+                BaseMessages.getString(PKG,
+                    "StandardizePhoneNumberDialog.ColumnInfo.IsValidNumberField.Label"),
+                ColumnInfo.COLUMN_TYPE_TEXT, new String[] {""}, false)};
+
+    columns[0].setToolTip(
+        BaseMessages.getString(PKG, "StandardizePhoneNumberDialog.ColumnInfo.InputField.Tooltip"));
+    columns[1].setToolTip(
+        BaseMessages.getString(PKG, "StandardizePhoneNumberDialog.ColumnInfo.OutputField.Tooltip"));
+    columns[1].setUsingVariables(true);
+    columns[2].setToolTip(BaseMessages.getString(PKG,
+        "StandardizePhoneNumberDialog.ColumnInfo.CountryField.Tooltip"));
+    columns[3].setToolTip(BaseMessages.getString(PKG,
+        "StandardizePhoneNumberDialog.ColumnInfo.DefaultCountry.Tooltip"));
+    columns[4].setToolTip(
+        BaseMessages.getString(PKG, "StandardizePhoneNumberDialog.ColumnInfo.NumberFormat.Tooltip"));
+    columns[5].setUsingVariables(true);
+    columns[5].setToolTip(BaseMessages.getString(PKG,
+        "StandardizePhoneNumberDialog.ColumnInfo.NumberTypeField.Tooltip"));
+    columns[6].setUsingVariables(true);
+    columns[6].setToolTip(BaseMessages.getString(PKG,
+        "StandardizePhoneNumberDialog.ColumnInfo.IsValidNumberField.Tooltip"));
+     
+    wFields = new TableView(this.getVariables(), shell, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, columns,
+        0, e -> input.setChanged(), props);
+    wFields.setLayoutData(
+        new FormDataBuilder().left().fullWidth().top(lblFields, margin).bottom(hSpacer, -margin).result());
+    wFields.getTable().addListener(SWT.Resize, new ColumnsResizer(2, 20, 20, 10, 12, 12, 12, 8));
+
+    // Search the fields in the background
+    //
+    final Runnable runnable = () -> {
+
+      TransformMeta transformMeta = pipelineMeta.findTransform(transformName);
+      if (transformMeta != null) {
+        try {
+          IRowMeta rowMeta = pipelineMeta.getPrevTransformFields(variables, transformMeta);
+
+          final List<String> inputFields = new ArrayList<>();
+
+          if (rowMeta != null) {
+
+            for (IValueMeta valueMeta : rowMeta.getValueMetaList()) {
+              inputFields.add(valueMeta.getName());
+            }
+
+            // Sort by name
+            String[] fieldNames = Const.sortStrings(inputFields.toArray(new String[0]));
+            columns[0].setComboValues(fieldNames);
+            columns[2].setComboValues(fieldNames);
+          }
+
+          // Display in red missing field names
+          Display.getDefault().asyncExec(new Runnable() {
+            public void run() {
+              if (!wFields.isDisposed()) {
+                for (int i = 0; i < wFields.table.getItemCount(); i++) {
+                  TableItem item = wFields.table.getItem(i);
+
+                  // Input field
+                  if (!Utils.isEmpty(item.getText(1))) {
+                    if (!inputFields.contains(item.getText(1))) {
+                      item.setBackground(GuiResource.getInstance().getColorRed());
+                    }
+                  }
+
+                  // Country field
+                  if (!Utils.isEmpty(item.getText(3))) {
+                    if (!inputFields.contains(item.getText(3))) {
+                      item.setBackground(GuiResource.getInstance().getColorRed());
+                    }
+                  }
+                }
+              }
+            }
+          });
+
+        } catch (HopException e) {
+          logError(BaseMessages.getString(PKG, "System.Dialog.GetFieldsFailed.Message"));
+        }
+      }
+    };
+    new Thread(runnable).start();
+    
+    getData();
+    input.setChanged(changed);
+    
+    BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel());
+
+    return transformName;
+  }
+
+  private void cancel() {
+    transformName = null;
+    input.setChanged(changed);
+    dispose();
+  }
+  
+  private void ok() {
+    if (Utils.isEmpty(wTransformName.getText())) {
+      return;
+    }
+
+    // Save transform name
+    transformName = wTransformName.getText();
+
+    List<StandardizePhoneField> standardizes = new ArrayList<>();
+    for (int i = 0; i < wFields.nrNonEmpty(); i++) {
+      TableItem item = wFields.getNonEmpty(i);
+
+      StandardizePhoneField standardize = new StandardizePhoneField();
+      standardize.setInputField(StringUtils.stripToNull(item.getText(1)));
+      standardize.setOutputField(StringUtils.stripToNull(item.getText(2)));
+      standardize.setCountryField(StringUtils.stripToNull(item.getText(3)));
+      standardize.setDefaultCountry(StringUtils.stripToNull(item.getText(4)));
+      standardize.setNumberFormat(StringUtils.stripToNull(item.getText(5)));
+      standardize.setNumberTypeField(item.getText(6));
+      standardize.setIsValidNumberField(StringUtils.stripToNull(item.getText(7)));
+      standardizes.add(standardize);
+    }
+    input.setFields(standardizes);
+
+    dispose();
+  }  
+}
diff --git a/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMeta.java b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMeta.java
new file mode 100644
index 0000000..57e7b39
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMeta.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.hop.core.CheckResult;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.ICheckResult;
+import org.apache.hop.core.annotations.Transform;
+import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.row.value.ValueMetaFactory;
+import org.apache.hop.core.util.Utils;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
+import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.pipeline.Pipeline;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.transform.BaseTransformMeta;
+import org.apache.hop.pipeline.transform.ITransform;
+import org.apache.hop.pipeline.transform.ITransformMeta;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+
+@Transform(id = "StandardizePhoneNumber", image = "standardizephonenumber.svg",
+    name = "i18n::StandardizePhoneNumber.Name",
+    description = "i18n::StandardizePhoneNumber.Description",
+    categoryDescription = "i18n:org.apache.hop.pipeline.transform:BaseTransform.Category.DataQuality",
+    documentationUrl = "/pipeline/transforms/standardizephonenumber.html")
+public class StandardizePhoneNumberMeta extends BaseTransformMeta
+    implements ITransformMeta<StandardizePhoneNumber, StandardizePhoneNumberData>, Serializable {
+
+  private static final Class<?> PKG = StandardizePhoneNumberMeta.class; // For Translator
+
+  private static final Set<PhoneNumberFormat> SUPPORTED_FORMATS = EnumSet.of(PhoneNumberFormat.E164,
+      PhoneNumberFormat.INTERNATIONAL, PhoneNumberFormat.NATIONAL, PhoneNumberFormat.RFC3966);
+
+
+
+  /** The phone number to standardize */
+  @HopMetadataProperty(key = "field", groupKey = "fields",
+      injectionGroupDescription = "StandardizePhoneNumber.Injection.Fields",
+      injectionKeyDescription = "StandardizePhoneNumber.Injection.Field")
+  private List<StandardizePhoneField> fields = new ArrayList<>();
+
+
+  public StandardizePhoneNumberMeta() {
+    super();
+  }
+
+  public StandardizePhoneNumberMeta(StandardizePhoneNumberMeta meta) {
+    super();
+
+    for (StandardizePhoneField field : meta.getFields()) {
+      fields.add(new StandardizePhoneField(field));
+    }
+  }
+
+
+  @Override
+  public Object clone() {
+    return new StandardizePhoneNumberMeta(this);
+  }
+
+  @Override
+  public ITransform createTransform(TransformMeta transformMeta, StandardizePhoneNumberData data,
+      int copyNr, PipelineMeta pipelineMeta, Pipeline pipeline) {
+    return new StandardizePhoneNumber(transformMeta, this, data, copyNr, pipelineMeta, pipeline);
+  }
+
+
+  @Override
+  public void setDefault() {}
+
+
+  @Override
+  public void getFields(IRowMeta inputRowMeta, String name, IRowMeta[] info,
+      TransformMeta nextTransform, IVariables variables, IHopMetadataProvider metadataProvider)
+      throws HopTransformException {
+    try {
+      // add the extra fields if specified
+      for (StandardizePhoneField standardize : this.getFields()) {
+
+        // add the output fields if specified
+        int index = inputRowMeta.indexOfValue(standardize.getInputField());
+        IValueMeta valueMeta = inputRowMeta.getValueMeta(index);
+        if (!Utils.isEmpty(standardize.getOutputField())) {
+          // created output field only if name changed
+          if (!standardize.getOutputField().equals(standardize.getInputField())) {
+
+            valueMeta = ValueMetaFactory.createValueMeta(standardize.getOutputField(),
+                IValueMeta.TYPE_STRING);
+
+            inputRowMeta.addValueMeta(valueMeta);
+          }
+        }
+        valueMeta.setOrigin(name);
+
+        // add result phone number type
+        if (!Utils.isEmpty(standardize.getNumberTypeField())) {
+          valueMeta = ValueMetaFactory.createValueMeta(standardize.getNumberTypeField(),
+              IValueMeta.TYPE_STRING);
+          valueMeta.setOrigin(name);
+          inputRowMeta.addValueMeta(valueMeta);
+        }
+
+        // add result is valid number
+        if (!Utils.isEmpty(standardize.getIsValidNumberField())) {
+          valueMeta = ValueMetaFactory.createValueMeta(standardize.getIsValidNumberField(),
+              IValueMeta.TYPE_BOOLEAN);
+          valueMeta.setOrigin(name);
+          inputRowMeta.addValueMeta(valueMeta);
+        }
+      }
+    } catch (Exception e) {
+      throw new HopTransformException(e);
+    }
+  }
+
+
+  @Override
+  public void check(List<ICheckResult> remarks, PipelineMeta pipelineMeta,
+      TransformMeta transformMeta, IRowMeta prev, String[] input, String[] output, IRowMeta info,
+      IVariables variables, IHopMetadataProvider metadataProvider) {
+
+    // See if we have fields from previous steps
+    if (prev == null || prev.size() == 0) {
+      remarks
+          .add(new CheckResult(ICheckResult.TYPE_RESULT_WARNING,
+              BaseMessages.getString(PKG,
+                  "StandardizePhoneNumberMeta.CheckResult.NotReceivingFieldsFromPreviousTransforms"),
+              transformMeta));
+    } else {
+      remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_OK,
+          BaseMessages.getString(PKG,
+              "StandardizePhoneNumberMeta.CheckResult.ReceivingFieldsFromPreviousTransforms", prev.size()), //$NON-NLS-1$
+          transformMeta));
+    }
+
+    // See if there are input streams leading to this step!
+    if (input.length > 0) {
+      remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_OK,
+          BaseMessages.getString(PKG, "StandardizePhoneNumberMeta.CheckResult.ReceivingInfoFromOtherTransforms"),
+          transformMeta));
+
+      // Check only if input fields
+      for (StandardizePhoneField standardize : fields) {
+
+        // See if there are missing input streams
+        IValueMeta valueMeta = prev.searchValueMeta(standardize.getInputField());
+        if (valueMeta == null) {
+          String message =
+              BaseMessages.getString(PKG, "StandardizePhoneNumberMeta.CheckResult.MissingInputField",
+                  Const.NVL(standardize.getInputField(), standardize.getOutputField()));
+          remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, transformMeta));
+        }
+
+        // See if there are missing input streams
+        valueMeta = prev.searchValueMeta(standardize.getCountryField());
+        if (valueMeta == null) {
+          String message = BaseMessages.getString(PKG,
+              "StandardizePhoneNumberMeta.CheckResult.MissingCountryField",
+              standardize.getCountryField());
+          remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, transformMeta));
+        }
+      }
+
+    } else {
+      remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR,
+          BaseMessages.getString(PKG, "StandardizePhoneNumberMeta.CheckResult.NotReceivingInfoFromOtherTransforms"),
+          transformMeta));
+    }
+
+  }
+
+  @Override
+  public StandardizePhoneNumberData getTransformData() {
+    return new StandardizePhoneNumberData();
+  }
+
+  public String[] getSupportedFormats() {
+
+    ArrayList<String> result = new ArrayList<>();
+    for (PhoneNumberFormat format : SUPPORTED_FORMATS) {
+      result.add(format.name());
+    }
+
+    return result.toArray(new String[result.size()]);
+  }
+
+  public String[] getSupportedCountries() {
+
+    PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
+
+    ArrayList<String> result = new ArrayList<>();
+    for (String region : phoneUtil.getSupportedRegions()) {
+      result.add(region);
+    }
+
+    return Const.sortStrings(result.toArray(new String[0]));
+  }
+
+  public List<StandardizePhoneField> getFields() {
+    return this.fields;
+  }
+
+  public void setFields(final List<StandardizePhoneField> standardizes) {
+    this.fields = standardizes;
+  }
+}
diff --git a/plugins/transforms/standardizephonenumber/src/main/resources/org/apache/hop/pipeline/transforms/standardizephonenumber/messages/messages_en_US.properties b/plugins/transforms/standardizephonenumber/src/main/resources/org/apache/hop/pipeline/transforms/standardizephonenumber/messages/messages_en_US.properties
new file mode 100644
index 0000000..d5ea827
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/resources/org/apache/hop/pipeline/transforms/standardizephonenumber/messages/messages_en_US.properties
@@ -0,0 +1,59 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+#
+StandardizePhoneNumber.Name=Standardize phone number
+StandardizePhoneNumber.Description=Normalize phone number in a standardized and consistent manner using Google libphonenumber library.
+StandardizePhoneNumberMeta.CheckResult.ReceivingFieldsFromPreviousTransforms=Transform is connected to previous one, receiving {0} fields.
+StandardizePhoneNumberMeta.CheckResult.NotReceivingFieldsFromPreviousTransforms= Not receiving any fields from previous transforms\!
+StandardizePhoneNumberMeta.CheckResult.ReceivingInfoFromOtherTransforms=Transform is receiving info from other transforms.
+StandardizePhoneNumberMeta.CheckResult.NotReceivingInfoFromOtherTransforms=No input received from other transforms\!
+StandardizePhoneNumberMeta.CheckResult.MissingInputField=Missing input field: [{0}]
+StandardizePhoneNumberMeta.CheckResult.MissingCountryField=Missing country input field: [{0}]
+StandardizePhoneNumberDialog.Shell.Title=Standardize phone number
+StandardizePhoneNumberDialog.Fields.Label=Fields to standardize
+StandardizePhoneNumberDialog.ColumnInfo.InputField.Label=Input field
+StandardizePhoneNumberDialog.ColumnInfo.InputField.Tooltip=The field holding the phone numbers from the input data.
+StandardizePhoneNumberDialog.ColumnInfo.OutputField.Label=Output field  
+StandardizePhoneNumberDialog.ColumnInfo.OutputField.Tooltip=Leave this field empty if you want to update the input field in stream\n. Otherwise a new field (string) will be added to the output data.
+StandardizePhoneNumberDialog.ColumnInfo.CountryField.Label=Country field
+StandardizePhoneNumberDialog.ColumnInfo.CountryField.Tooltip=The field holding the country code from the input data. The country code is required to be in the ISO alpha-2.
+StandardizePhoneNumberDialog.ColumnInfo.DefaultCountry.Label=Default country
+StandardizePhoneNumberDialog.ColumnInfo.DefaultCountry.Tooltip=The default country code to use if input data from country field is empty or invalid
+StandardizePhoneNumberDialog.ColumnInfo.NumberFormat.Label=Format
+StandardizePhoneNumberDialog.ColumnInfo.NumberFormat.Tooltip=The format to be used to standardize the phone number\n E164 +41446681800\n INTERNATIONAL +41 44 668 18 00\n NATIONAL 044 668 18 00\n RFC3966 tel:+41-44-668-18-00
+StandardizePhoneNumberDialog.ColumnInfo.NumberTypeField.Label=Number type field
+StandardizePhoneNumberDialog.ColumnInfo.NumberTypeField.Tooltip=The result field indicates the type of a processed phone number, such as fixed line, mobile...
+StandardizePhoneNumberDialog.ColumnInfo.IsValidNumberField.Label=Is valid field
+StandardizePhoneNumberDialog.ColumnInfo.IsValidNumberField.Tooltip=The result field indicates whether a phone number is supposed to be valid
+StandardizePhoneNumber.Injection.Fields=Fields to standardize
+StandardizePhoneNumber.Injection.InputField=Input field
+StandardizePhoneNumber.Injection.OutputField=Output field  
+StandardizePhoneNumber.Injection.CountryField=Country field
+StandardizePhoneNumber.Injection.DefaultCountry=Default country
+StandardizePhoneNumber.Injection.NumberFormat=Number format
+StandardizePhoneNumber.Injection.NumberTypeField=Number type
+StandardizePhoneNumber.Injection.IsValidNumberField=Is valid
+StandardizePhoneNumber.Log.ProcessPhoneNumberError=Error standardize field [{0}] with value [{1}]
+StandardizePhoneNumber.Log.StartedProcessing=Started transform processing
+StandardizePhoneNumber.Log.WroteRowToNextTransform=Wrote row to next transform: {0}
+StandardizePhoneNumber.Log.RegionNotSupported=Region [{0}] not supported
+StandardizePhoneNumber.Log.CountryFieldNotFound=Error country field not found [{0}]
+StandardizePhoneNumber.Log.InputFieldNotFound=Input field not found: [{0}]
+
+
diff --git a/plugins/transforms/standardizephonenumber/src/main/resources/standardizephonenumber.svg b/plugins/transforms/standardizephonenumber/src/main/resources/standardizephonenumber.svg
new file mode 100644
index 0000000..8b6e727
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/resources/standardizephonenumber.svg
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
+<path id="path5_1_" fill="#3D6480" d="M13.4,1.256c-6.526,0-11.836,5.636-11.836,12.564S6.874,26.383,13.4,26.383
+	c0.403,0,0.729-0.348,0.729-0.773c0-0.428-0.326-0.774-0.729-0.774c-5.723,0-10.377-4.94-10.377-11.014S7.678,2.806,13.4,2.806
+	s10.377,4.941,10.377,11.015c0,2.538-1.273,5.055-3.094,6.121c-0.662,0.385-1.381,0.578-2.146,0.584
+	c0.459-0.289,0.856-0.683,1.151-1.177c0.06-0.094,0.135-0.174,0.172-0.276c0.238-0.606,0.261-1.295,0.402-1.937
+	c0.178-0.819-3.375-2.417-3.684-1.396c-0.111,0.38-0.283,1.576-0.508,1.891c-0.199,0.279-0.69,0.148-0.998-0.129
+	c-0.809-0.732-1.713-1.81-2.506-2.659l0.002-0.001c-0.021-0.022-0.045-0.048-0.066-0.07c-0.021-0.023-0.045-0.048-0.066-0.071l0,0
+	c-0.803-0.841-1.816-1.799-2.506-2.66c-0.261-0.326-0.387-0.846-0.121-1.059c0.297-0.238,1.424-0.417,1.78-0.537
+	c0.961-0.327-0.543-4.1-1.315-3.911c-0.604,0.15-1.252,0.173-1.824,0.425c-0.096,0.043-0.172,0.123-0.26,0.185
+	c-2.028,1.365-2.289,4.679-0.31,7.148c0.754,0.944,1.542,1.858,2.353,2.75l-0.004,0.004c0.021,0.022,0.045,0.046,0.068,0.067
+	c0.021,0.024,0.043,0.05,0.064,0.074l0.004-0.006c0.84,0.861,1.837,2.127,3.455,3.273c3.41,2.416,6.025,1.742,7.565,0.845
+	c2.659-1.554,3.851-4.875,3.851-7.476C25.238,6.892,19.928,1.256,13.4,1.256z"/>
+<path id="path4164-2_1_" fill="#FF9C04" stroke="#FF9C04" stroke-width="0.2227" stroke-linecap="round" stroke-linejoin="round" d="
+	M24.67,28.57c-0.311-1.068-0.58-1.953-0.602-1.965c-0.02-0.014-0.381-0.092-0.801-0.176c-0.422-0.084-1.414-0.289-2.204-0.453
+	l-1.438-0.303l2.237-0.477l2.237-0.479l0.05-0.142c0.026-0.078,0.221-0.75,0.43-1.493c0.41-1.452,0.621-2.093,0.677-2.041
+	c0.02,0.019,0.258,0.846,0.53,1.84s0.501,1.813,0.509,1.82c0.012,0.016,1.834,0.409,3.396,0.735c0.598,0.125,1.08,0.231,1.073,0.236
+	c-0.008,0.005-1.018,0.219-2.244,0.475l-2.231,0.467l-0.526,1.949l-0.526,1.951L24.67,28.57z"/>
+<path id="path4840_1_" fill="#FF9C04" stroke="#FF9C04" stroke-width="0.1134" stroke-linecap="round" stroke-linejoin="round" d="
+	M16.904,31.152c-0.031-0.086-0.156-0.496-0.277-0.912c-0.339-1.17-0.346-1.178-1.209-1.461c-0.416-0.137-1.06-0.313-1.428-0.396
+	c-0.367-0.08-0.63-0.175-0.583-0.209s0.636-0.183,1.31-0.329c0.672-0.146,1.275-0.292,1.34-0.324
+	c0.066-0.033,0.295-0.588,0.509-1.235s0.403-1.188,0.421-1.201s0.207,0.497,0.422,1.135s0.459,1.2,0.541,1.249
+	c0.084,0.051,0.691,0.217,1.352,0.367c1.27,0.293,1.502,0.383,1.185,0.455c-2.562,0.574-2.577,0.586-3.056,1.934
+	c-0.194,0.545-0.379,1.014-0.409,1.037C16.987,31.286,16.937,31.236,16.904,31.152z"/>
+<path id="path4842_1_" fill="#FF9C04" stroke="#FF9C04" stroke-width="0.0351" stroke-linecap="round" stroke-linejoin="round" d="
+	M28.195,21.343c-0.012-0.016-0.093-0.296-0.18-0.622c-0.086-0.326-0.18-0.621-0.207-0.656c-0.08-0.104-0.537-0.271-1.323-0.483
+	c-0.146-0.04-0.254-0.081-0.239-0.091c0.014-0.012,0.291-0.086,0.617-0.168c0.325-0.082,0.664-0.172,0.752-0.199l0.16-0.049
+	l0.135-0.469c0.236-0.818,0.307-1.023,0.33-0.986c0.012,0.02,0.111,0.346,0.221,0.725c0.11,0.379,0.217,0.701,0.24,0.717
+	c0.021,0.017,0.361,0.115,0.754,0.224c0.393,0.106,0.715,0.204,0.717,0.221c0.002,0.015-0.258,0.099-0.576,0.188
+	c-0.317,0.088-0.639,0.192-0.711,0.233c-0.189,0.104-0.272,0.265-0.439,0.849C28.303,21.263,28.24,21.404,28.195,21.343z"/>
+</svg>
diff --git a/plugins/transforms/standardizephonenumber/src/main/samples/transforms/standardizephonenumber.hpl b/plugins/transforms/standardizephonenumber/src/main/samples/transforms/standardizephonenumber.hpl
new file mode 100644
index 0000000..e2c4110
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/main/samples/transforms/standardizephonenumber.hpl
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>standardizephonenumber</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2021/10/08 20:16:07.061</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2021/10/08 20:16:07.061</modified_date>
+    <key_for_session_key>H4sIAAAAAAAAAAMAAAAAAAAAAAA=</key_for_session_key>
+    <is_key_private>N</is_key_private>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>Data grid</from>
+      <to>Standardize phone number</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>Data grid</name>
+    <type>DataGrid</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <set_empty_string>N</set_empty_string>
+        <length>-1</length>
+        <name>Input</name>
+        <precision>-1</precision>
+        <type>String</type>
+      </field>
+      <field>
+        <set_empty_string>N</set_empty_string>
+        <length>-1</length>
+        <name>Country</name>
+        <precision>-1</precision>
+        <type>String</type>
+      </field>
+    </fields>
+    <data>
+      <line>
+        <item>+32495400200</item>
+        <item>FR</item>
+      </line>
+      <line>
+        <item>0032495400200</item>
+        <item>BE</item>
+      </line>
+      <line>
+        <item>0499500158</item>
+        <item>BE</item>
+      </line>
+      <line>
+        <item>0499500158</item>
+        <item/>
+      </line>
+      <line>
+        <item>0388902406</item>
+        <item>FR</item>
+      </line>
+      <line>
+        <item>888.555.1212 x123</item>
+        <item>US</item>
+      </line>
+      <line>
+        <item>999</item>
+        <item>FR</item>
+      </line>
+      <line>
+        <item/>
+        <item>FR</item>
+      </line>
+      <line>
+        <item>(908)123-4567</item>
+        <item>US</item>
+      </line>
+      <line>
+        <item>#(210) 567-9451</item>
+        <item/>
+      </line>
+      <line>
+        <item>Direct: (888) 555-1212</item>
+        <item>US</item>
+      </line>
+      <line>
+        <item>987-654-3211</item>
+        <item/>
+      </line>
+    </data>
+    <attributes/>
+    <GUI>
+      <xloc>112</xloc>
+      <yloc>112</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Standardize phone number</name>
+    <type>StandardizePhoneNumber</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <country>Country</country>
+        <defaultCountry>BE</defaultCountry>
+        <input>Input</input>
+        <format>RFC3966</format>
+        <output>RFC3966</output>
+      </field>
+      <field>
+        <country>Country</country>
+        <defaultCountry>BE</defaultCountry>
+        <input>Input</input>
+        <format>INTERNATIONAL</format>
+        <output>INTERNATIONAL_BE</output>
+      </field>
+      <field>
+        <country>Country</country>
+        <defaultCountry>FR</defaultCountry>
+        <input>Input</input>
+        <format>INTERNATIONAL</format>
+        <output>INTERNATIONAL_FR</output>
+      </field>
+      <field>
+        <country>Country</country>
+        <defaultCountry>US</defaultCountry>
+        <input>Input</input>
+        <format>INTERNATIONAL</format>
+        <output>INTERNATIONAL_US</output>
+      </field>
+      <field>
+        <country>Country</country>
+        <defaultCountry>FR</defaultCountry>
+        <input>Input</input>
+        <format>E164</format>
+        <output>E164</output>
+      </field>
+      <field>
+        <country>Country</country>
+        <defaultCountry>FR</defaultCountry>
+        <input>Input</input>
+        <isvalidnumber>ISVALID</isvalidnumber>
+        <format>NATIONAL</format>
+        <numbertype>TYPE</numbertype>
+        <output>NATIONAL</output>
+      </field>
+    </fields>
+    <attributes/>
+    <GUI>
+      <xloc>272</xloc>
+      <yloc>112</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/plugins/transforms/standardizephonenumber/src/test/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMetaInjectionTest.java b/plugins/transforms/standardizephonenumber/src/test/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMetaInjectionTest.java
new file mode 100644
index 0000000..37c8327
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/test/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMetaInjectionTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.hop.core.injection.BaseMetadataInjectionTest;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironment;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class StandardizePhoneNumberMetaInjectionTest extends BaseMetadataInjectionTest<StandardizePhoneNumberMeta> {
+  @ClassRule public static RestoreHopEngineEnvironment env = new RestoreHopEngineEnvironment();
+
+  @Before
+  public void setup() throws Exception {
+    setup(new StandardizePhoneNumberMeta());
+  }
+
+  @Test
+  public void test() throws Exception {
+    check("input", () -> meta.getFields().get(0).getInputField());
+    check("output", () -> meta.getFields().get(0).getOutputField());
+    check("format", () -> meta.getFields().get(0).getNumberFormat());   
+    check("country", () -> meta.getFields().get(0).getCountryField());
+    check("defaultCountry", () -> meta.getFields().get(0).getDefaultCountry());   
+    check("numbertype", () -> meta.getFields().get(0).getNumberTypeField());
+    check("isvalidnumber", () -> meta.getFields().get(0).getIsValidNumberField());
+  }
+}
diff --git a/plugins/transforms/standardizephonenumber/src/test/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMetaTest.java b/plugins/transforms/standardizephonenumber/src/test/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMetaTest.java
new file mode 100644
index 0000000..67a34d2
--- /dev/null
+++ b/plugins/transforms/standardizephonenumber/src/test/java/org/apache/hop/pipeline/transforms/standardizephonenumber/StandardizePhoneNumberMetaTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.standardizephonenumber;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironment;
+import org.apache.hop.pipeline.transforms.loadsave.LoadSaveTester;
+import org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator;
+import org.junit.ClassRule;
+import org.junit.Test;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class StandardizePhoneNumberMetaTest {
+  @ClassRule public static RestoreHopEngineEnvironment env = new RestoreHopEngineEnvironment();
+
+  /** @throws HopException */
+
+  public void test() throws HopException {
+    List<String> attributes =
+        Arrays.asList(
+            "fields");
+
+    Map<String, String> getterMap = new HashMap<>();
+    Map<String, String> setterMap = new HashMap<>();
+
+    Map<String, IFieldLoadSaveValidator<?>> fieldLoadSaveValidatorAttributeMap = new HashMap<>();
+   
+    LoadSaveTester<StandardizePhoneNumberMeta> loadSaveTester =
+        new LoadSaveTester<>(
+            StandardizePhoneNumberMeta.class,
+            attributes,
+            getterMap,
+            setterMap,
+            fieldLoadSaveValidatorAttributeMap,
+            new HashMap<>());
+
+    loadSaveTester.testSerialization();
+  }
+
+}