diff --git a/packages/fxa-settings/src/components/DeviceInfoBlock/index.tsx b/packages/fxa-settings/src/components/DeviceInfoBlock/index.tsx
index 06266db1168..0286007d885 100644
--- a/packages/fxa-settings/src/components/DeviceInfoBlock/index.tsx
+++ b/packages/fxa-settings/src/components/DeviceInfoBlock/index.tsx
@@ -19,38 +19,52 @@ export const DeviceInfoBlock = ({ remoteMetadata }: DeviceInfoBlockProps) => {
city,
region,
country,
+ countryCode,
} = remoteMetadata;
+ const currentLocale = document.documentElement.lang || 'en-US';
+ let localizedCountry = country;
+
+ if (countryCode && typeof Intl !== 'undefined' && Intl.DisplayNames) {
+ try {
+ const regionNames = new Intl.DisplayNames([currentLocale], {
+ type: 'region',
+ });
+ localizedCountry = regionNames.of(countryCode) || country;
+ } catch (e) {
+ // Fallback to raw country name if Intl fails
+ }
+ }
const LocalizedLocation = () => {
if (city && region && country) {
return (
{`${city}, ${region}, ${country} (estimated)`}
+ vars={{ city, region, country: localizedCountry }}
+ >{`${city}, ${region}, ${localizedCountry} (estimated)`}
);
}
if (region && country) {
return (
{`${region}, ${country} (estimated)`}
+ vars={{ region, country: localizedCountry }}
+ >{`${region}, ${localizedCountry} (estimated)`}
);
}
if (city && country) {
return (
{`${city}, ${country} (estimated)`}
+ vars={{ city, country: localizedCountry }}
+ >{`${city}, ${localizedCountry} (estimated)`}
);
}
if (country) {
return (
{`${country} (estimated)`}
+ vars={{ country: localizedCountry }}
+ >{`${localizedCountry} (estimated)`}
);
}
return (
diff --git a/packages/fxa-settings/src/lib/types.ts b/packages/fxa-settings/src/lib/types.ts
index 0faff1d7878..2a5b8be6cf4 100644
--- a/packages/fxa-settings/src/lib/types.ts
+++ b/packages/fxa-settings/src/lib/types.ts
@@ -69,6 +69,7 @@ export type RemoteMetadata = {
deviceOS: string;
ipAddress: string;
country?: string;
+ countryCode?: string;
region?: string;
city?: string;
};
diff --git a/packages/fxa-shared/connected-services/formatters.ts b/packages/fxa-shared/connected-services/formatters.ts
index bb43d12d3eb..09d06e8bdc4 100644
--- a/packages/fxa-shared/connected-services/formatters.ts
+++ b/packages/fxa-shared/connected-services/formatters.ts
@@ -50,47 +50,18 @@ export class ClientFormatter implements IClientFormatter {
client: AttachedClient,
request: IClientFormatterRequest
) {
- let language;
if (!client.location) {
client.location = {};
} else {
const location = client.location;
- try {
- language = determineLocale(
- request.app.acceptLanguage,
- this.supportedLanguages
- );
-
- // For English, we can leave all the location components intact.
- // For other languages, only return what we can translate
- if (language[0] === 'e' || language[1] === 'n') {
- client.location = {
- city: location.city,
- country: location.country,
- state: location.state,
- stateCode: location.stateCode,
- };
- } else if (location.countryCode) {
- const territoriesLang =
- language === 'en-US' ? 'en-US-POSIX' : language;
- const territories = require(`cldr-localenames-full/main/${territoriesLang}/territories.json`);
- client.location = {
- country:
- territories.main[language].localeDisplayNames.territories[
- location.countryCode
- ],
- };
- }
- } catch (err) {
- const log = this.logProvider();
- log.debug('attached-clients.formatLocation.warning', {
- err: err.message,
- languages: request.app.acceptLanguage,
- language,
- location,
- });
- client.location = {};
- }
+ // ClientFormatter should be locale-agnostic and return consistent identifiers across all requests.
+ client.location = {
+ city: location.city,
+ country: location.country,
+ countryCode: location.countryCode,
+ state: location.state,
+ stateCode: location.stateCode,
+ };
}
return client;
}
diff --git a/packages/fxa-shared/connected-services/models/AttachedClient.ts b/packages/fxa-shared/connected-services/models/AttachedClient.ts
index 0e10224a88a..dac8d76a236 100644
--- a/packages/fxa-shared/connected-services/models/AttachedClient.ts
+++ b/packages/fxa-shared/connected-services/models/AttachedClient.ts
@@ -21,6 +21,7 @@ export type AttachedClient = {
lastAccessTimeFormatted?: string;
approximateLastAccessTime?: number;
approximateLastAccessTimeFormatted?: string;
+ countryCode?: string | null;
};
export const attachedClientsDefaults: AttachedClient = {
diff --git a/packages/fxa-shared/test/connected-services/formatters.ts b/packages/fxa-shared/test/connected-services/formatters.ts
index 1cd600326e4..e74c47d5299 100644
--- a/packages/fxa-shared/test/connected-services/formatters.ts
+++ b/packages/fxa-shared/test/connected-services/formatters.ts
@@ -62,8 +62,7 @@ describe('connected-services/formatters', () => {
assert.exists(client.location?.state);
assert.exists(client.location?.stateCode);
assert.exists(client.location?.country);
- // Not set, is this a bug?
- // assert.exists(client.location?.countryCode);
+ assert.exists(client.location?.countryCode);
});
it('formats DE location', () => {
@@ -71,15 +70,21 @@ describe('connected-services/formatters', () => {
client.location = {
city: 'Berlin',
countryCode: 'DE',
+ country: 'Germany',
+ state: 'Berlin',
+ stateCode: 'BE'
};
clientFormatter.formatLocation(client, request);
+ assert.exists(client.location?.city);
+ assert.exists(client.location?.state);
+ assert.exists(client.location?.stateCode);
assert.exists(client.location?.country);
- // Not set, is this a bug?
- // assert.exists(client.location?.city);
- // assert.exists(client.location?.state);
- // assert.exists(client.location?.stateCode);
- // assert.exists(client.location?.countryCode);
+ assert.exists(client.location?.countryCode);
+
+ // Assert we are NOT localizing on the backend anymore
+ assert.strictEqual(client.location?.country, 'Germany'); // Should remain as input
+ assert.strictEqual(client.location?.countryCode, 'DE');
});
it('formats timestamps', () => {