Skip to content

Commit 9ac79cf

Browse files
cpcloudclaude
andcommitted
feat(locale): add FormatPhoneNumber with international support
Parses and formats phone numbers using nyaruka/phonenumbers. Uses region comparison to choose NATIONAL vs INTERNATIONAL format, with country-code fallback for fictional numbers (e.g. 555-xxxx). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 152f34d commit 9ac79cf

5 files changed

Lines changed: 81 additions & 1 deletion

File tree

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/itchyny/gojq v0.12.18
1818
github.com/mark3labs/mcp-go v0.46.0
1919
github.com/mozilla-ai/any-llm-go v0.9.0
20+
github.com/nyaruka/phonenumbers v1.6.12
2021
github.com/oklog/ulid/v2 v2.1.1
2122
github.com/spf13/cobra v1.10.2
2223
github.com/stretchr/testify v1.11.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
193193
github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
194194
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
195195
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
196+
github.com/nyaruka/phonenumbers v1.6.12 h1:aeGHjGQnfLhdN5/mZPevhoYMs13FWcQ0Vus0YQHh1Ec=
197+
github.com/nyaruka/phonenumbers v1.6.12/go.mod h1:IUu45lj2bSeYXQuxDyyuzOrdV10tyRa1YSsfH8EKN5c=
196198
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
197199
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
198200
github.com/ollama/ollama v0.18.3 h1:sOJhncLeA+ZlwLLjEksY393wojeYE52E1CF4E0ZgFN4=

internal/locale/phone.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2026 Phillip Cloud
2+
// Licensed under the Apache License, Version 2.0
3+
4+
package locale
5+
6+
import (
7+
"strings"
8+
9+
"github.com/nyaruka/phonenumbers"
10+
)
11+
12+
// FormatPhoneNumber formats a phone number string for display.
13+
// regionCode is an uppercase ISO 3166-1 alpha-2 code (e.g. "US").
14+
// Returns the original string unmodified if parsing fails.
15+
func FormatPhoneNumber(number, regionCode string) string {
16+
trimmed := strings.TrimSpace(number)
17+
if trimmed == "" {
18+
return ""
19+
}
20+
parsed, err := phonenumbers.Parse(trimmed, regionCode)
21+
if err != nil {
22+
return number
23+
}
24+
// Prefer region comparison (distinguishes US/CA under shared +1 code).
25+
// Fall back to country-code comparison for fictional numbers (e.g. 555-xxxx)
26+
// that parse successfully but return an empty region.
27+
parsedRegion := phonenumbers.GetRegionCodeForNumber(parsed)
28+
if parsedRegion != "" {
29+
if parsedRegion == regionCode {
30+
return phonenumbers.Format(parsed, phonenumbers.NATIONAL)
31+
}
32+
return phonenumbers.Format(parsed, phonenumbers.INTERNATIONAL)
33+
}
34+
if int(parsed.GetCountryCode()) == phonenumbers.GetCountryCodeForRegion(regionCode) {
35+
return phonenumbers.Format(parsed, phonenumbers.NATIONAL)
36+
}
37+
return phonenumbers.Format(parsed, phonenumbers.INTERNATIONAL)
38+
}

internal/locale/phone_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2026 Phillip Cloud
2+
// Licensed under the Apache License, Version 2.0
3+
4+
package locale_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
11+
"github.com/micasa-dev/micasa/internal/locale"
12+
)
13+
14+
func TestFormatPhoneNumber(t *testing.T) {
15+
t.Parallel()
16+
tests := []struct {
17+
name string
18+
number string
19+
region string
20+
want string
21+
}{
22+
{"US national", "5551234567", "US", "(555) 123-4567"},
23+
{"UK national", "02079460958", "GB", "020 7946 0958"},
24+
{"international prefix", "+442079460958", "US", "+44 20 7946 0958"},
25+
{"same-region prefix", "+15551234567", "US", "(555) 123-4567"},
26+
{"already formatted", "(555) 123-4567", "US", "(555) 123-4567"},
27+
{"cross-border shared code", "+16135551234", "US", "+1 613-555-1234"},
28+
{"garbage passthrough", "not a phone", "US", "not a phone"},
29+
{"empty string", "", "US", ""},
30+
{"whitespace only", " ", "US", ""},
31+
}
32+
for _, tt := range tests {
33+
t.Run(tt.name, func(t *testing.T) {
34+
t.Parallel()
35+
got := locale.FormatPhoneNumber(tt.number, tt.region)
36+
assert.Equal(t, tt.want, got)
37+
})
38+
}
39+
}

nix/package.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ buildGoModule {
1414
inherit pname version;
1515
src = gitignoreSource ../.;
1616
subPackages = [ "cmd/micasa" ];
17-
vendorHash = "sha256-r8zgXVRss4U3EA2iSs9YqLlNlWeANJXIKP8s1O75Wmw=";
17+
vendorHash = "sha256-uj8WCXGEfhTAsKRpL6ocFEblqrudq0hfKCgp8dC5fbo=";
1818
env.CGO_ENABLED = 0;
1919
preCheck = ''
2020
export HOME="$(mktemp -d)"

0 commit comments

Comments
 (0)