Skip to main content

Internationalization

|

The Magic Lane SDK for TypeScript provides extensive multilingual and localization support, ensuring seamless integration for global applications. By supporting a wide range of localizations, the SDK helps applications meet internationalization standards, enhance user engagement, and reduce friction for end-users across different markets.

Browser Language Detection

When running in a browser, the SDK automatically detects and uses the browser's preferred language by default. The browser language is determined from:

// Browser's preferred language
const browserLang = navigator.language; // e.g., "en-US", "fr-FR", "de-DE"

// All preferred languages (in order of preference)
const browserLangs = navigator.languages; // e.g., ["en-US", "en", "fr"]

The SDK will automatically select the best matching language from navigator.languages during initialization.

Set the SDK Language

To configure the SDK's language, select a language from the SdkSettings.languageList getter and assign it using the SdkSettings.language setter.

import { SdkSettings, Language } from '@magiclane/maps-sdk';

// Get the best language match for English
const engLang: Language | null = SdkSettings.getBestLanguageMatch("eng");
if (engLang) {
SdkSettings.language = engLang;
}

Manual Language Selection

You can override the browser's default language:

// Set to German
const germanLang = SdkSettings.getBestLanguageMatch("deu");
if (germanLang) {
SdkSettings.language = germanLang;
}

// Set to French
const frenchLang = SdkSettings.getBestLanguageMatch("fra");
if (frenchLang) {
SdkSettings.language = frenchLang;
}

// Set to Spanish
const spanishLang = SdkSettings.getBestLanguageMatch("spa");
if (spanishLang) {
SdkSettings.language = spanishLang;
}

Detecting Browser Language

Get the browser's language and match it to SDK language:

function setBrowserLanguage() {
// Get browser's primary language code
const browserLang = navigator.language; // e.g., "en-US"
const langCode = browserLang.split('-')[0]; // "en"

// Map common language codes to ISO 639-3
const langMap: { [key: string]: string } = {
'en': 'eng',
'fr': 'fra',
'de': 'deu',
'es': 'spa',
'it': 'ita',
'pt': 'por',
'ru': 'rus',
'zh': 'zho',
'ja': 'jpn',
'ko': 'kor',
'ar': 'ara',
'hi': 'hin'
};

const iso639_3 = langMap[langCode] || 'eng'; // Default to English
const sdkLang = SdkSettings.getBestLanguageMatch(iso639_3);

if (sdkLang) {
SdkSettings.language = sdkLang;
console.log(`SDK language set to: ${sdkLang.name}`);
}
}

// Call after SDK initialization
setBrowserLanguage();
Note

The languageCode follows the ISO 639-3 standard. Multiple variants may exist for a single language code. Further filtering can be applied using the regionCode field within the Language object, which adheres to the ISO 3166-1 standard.

Language List

Get all available languages:

import { SdkSettings, Language } from '@magiclane/maps-sdk';

// Get all supported languages
const languages: Language[] = SdkSettings.languageList;

languages.forEach(lang => {
console.log(`${lang.name} (${lang.languageCode})`);
});

What SDK Language Affects

Setting the SDK language modifies the following:

  • Landmark search results: The displayed names of landmarks
  • Overlay items: Names and details shown on the map and in search results
  • Landmark categories: The displayed category names
  • Overlays: The displayed overlay names
  • Navigation and routing instructions: Text-based instructions intended for on-screen display
    (Text-to-speech instructions remain unaffected)
  • name field of GemParameter objects returned by operations such as:
    • Weather forecasts
    • Overlay item previews
    • Traffic event previews
    • Content store parameters
    • Route extra information
    • Data source parameters
  • Content store item names: Names of downloadable road maps and styles
  • Wikipedia external information: Titles, descriptions, and localized URLs

Map Language

To ensure the map uses the same language all over the world, use the following code:

import { SdkSettings, MapLanguage } from '@magiclane/maps-sdk';

// Show translated location names (e.g., "Beijing" in English)
SdkSettings.mapLanguage = MapLanguage.automatic;

To show location names in their native language (where available) for the respective region, use this code:

// Show native location names (e.g., "北京市" for Beijing)
SdkSettings.mapLanguage = MapLanguage.native;

Example

For example, if the SDK language is set to English:

  • When MapLanguage is set to automatic, landmarks like Beijing are translated and displayed on the map as "Beijing."
  • When MapLanguage is set to native, landmarks remain in their local language and are displayed as "北京市."

Set the Unit of Measurement

Change between different unit systems using the unitSystem property of the SdkSettings class.

The following unit systems are supported:

UnitDistanceTemperature
metricKilometers and metersCelsius degrees
imperialUKMiles and yardsCelsius degrees
imperialUSMiles and feetFahrenheit degrees
import { SdkSettings, UnitSystem } from '@magiclane/maps-sdk';

// Metric system (km, meters, Celsius)
SdkSettings.unitSystem = UnitSystem.metric;

// Imperial UK (miles, yards, Celsius)
SdkSettings.unitSystem = UnitSystem.imperialUK;

// Imperial US (miles, feet, Fahrenheit)
SdkSettings.unitSystem = UnitSystem.imperialUS;

Auto-detect Browser Locale Unit System

function setBrowserUnitSystem() {
// Get browser's locale
const locale = navigator.language; // e.g., "en-US", "en-GB", "fr-FR"

// Countries using imperial US system
const imperialUSCountries = ['US', 'AS', 'GU', 'MP', 'PR', 'VI'];

// Countries using imperial UK system
const imperialUKCountries = ['GB', 'IE'];

const country = locale.split('-')[1] || '';

if (imperialUSCountries.includes(country)) {
SdkSettings.unitSystem = UnitSystem.imperialUS;
} else if (imperialUKCountries.includes(country)) {
SdkSettings.unitSystem = UnitSystem.imperialUK;
} else {
SdkSettings.unitSystem = UnitSystem.metric;
}

console.log(`Unit system set to: ${SdkSettings.unitSystem}`);
}

What Unit System Affects

This change will affect:

  • The values for distance interpolated in strings (both intended for display and TTS) such as navigation and routing instructions
  • The values provided by the map scale
  • The values for temperature used in weather forecasts
warning

Keep in mind that all values returned by numeric getters and required by numeric setters are expressed using SI (International System) units, regardless of the unitSystem setting:

  • Meters for distance
  • Seconds for time
  • Kilograms for mass
  • Meters per second for speed
  • Watts for power

Exceptions to this convention are explicitly documented in the API reference and user guide. For example, truck profile dimensions may use centimeters instead of SI units.

DateTime Convention

Most members returning a Date value use the UTC time zone.

// Working with UTC dates
const utcDate = new Date(); // Browser creates in local time
const utcTimestamp = Date.UTC(
utcDate.getUTCFullYear(),
utcDate.getUTCMonth(),
utcDate.getUTCDate(),
utcDate.getUTCHours(),
utcDate.getUTCMinutes(),
utcDate.getUTCSeconds()
);
warning

Some members return the local time of the trip's location, but should still be treated as UTC for consistency. These exceptions are documented in both the API reference and the user guide.

Tip

Use the TimezoneService class to convert between UTC and local time zones. See the TimezoneService guide for more details.

Number Separators

Numbers can be formatted using custom characters for decimal and digit group separators. These settings are controlled via the SdkSettings class.

Set the Decimal Separator

The decimal separator divides the whole and fractional parts of a number.

import { SdkSettings } from '@magiclane/maps-sdk';

// Use period (default in US)
SdkSettings.decimalSeparator = '.'; // 1234.56

// Use comma (common in Europe)
SdkSettings.decimalSeparator = ','; // 1234,56

Set the Digit Group Separator

The digit group separator is used to group large numbers (e.g., separating thousands).

// Use comma (default in US)
SdkSettings.digitGroupSeparator = ','; // 1,234.56

// Use period (common in Europe)
SdkSettings.digitGroupSeparator = '.'; // 1.234,56

// Use space (common in France)
SdkSettings.digitGroupSeparator = ' '; // 1 234,56

Auto-detect Browser Locale Number Format

function setBrowserNumberFormat() {
const testNumber = 1234.56;
const formatted = testNumber.toLocaleString(navigator.language);

// Try to detect separators from formatted number
// e.g., "1,234.56" (US) vs "1.234,56" (DE) vs "1 234,56" (FR)

if (formatted.includes(',') && formatted.indexOf(',') > formatted.indexOf('.')) {
// US format: 1,234.56
SdkSettings.digitGroupSeparator = ',';
SdkSettings.decimalSeparator = '.';
} else if (formatted.includes('.') && formatted.indexOf('.') < formatted.lastIndexOf(',')) {
// European format: 1.234,56
SdkSettings.digitGroupSeparator = '.';
SdkSettings.decimalSeparator = ',';
} else if (formatted.includes(' ')) {
// French format: 1 234,56
SdkSettings.digitGroupSeparator = ' ';
SdkSettings.decimalSeparator = ',';
}

console.log(`Number format: ${1234.56}${formatted}`);
}

ISO Code Conversions

Various methods require and provide different standards of ISO codes. Use the ISOCodeConversions class to convert country or language codes between formats.

Country Code Conversion

import { ISOCodeConversions, ISOCodeType } from '@magiclane/maps-sdk';

// Converting country ISO from ISO 3166-1 alpha-2 to ISO 3166-1 alpha-3
const res1 = ISOCodeConversions.convertCountryIso("BR", ISOCodeType.iso_3);
// Result: "BRA"

// Converting country ISO from ISO 3166-1 alpha-3 to ISO 3166-1 alpha-2
const res2 = ISOCodeConversions.convertCountryIso("BRA", ISOCodeType.iso_2);
// Result: "BR"

Language Code Conversion

// Converting language ISO from ISO 639-3 to ISO 639-1
const res3 = ISOCodeConversions.convertLanguageIso("hun", ISOCodeType.iso_2);
// Result: "hu"

// Converting language ISO from ISO 639-1 to ISO 639-3
const res4 = ISOCodeConversions.convertLanguageIso("hu", ISOCodeType.iso_3);
// Result: "hun"

Browser Locale to ISO Conversion

function getBrowserCountryISO3(): string | null {
const locale = navigator.language; // e.g., "en-US"
const countryCode = locale.split('-')[1]; // "US"

if (countryCode) {
return ISOCodeConversions.convertCountryIso(countryCode, ISOCodeType.iso_3);
}

return null;
}

const countryISO3 = getBrowserCountryISO3();
console.log('Country ISO 3166-1 alpha-3:', countryISO3); // "USA"

Complete Internationalization Setup

Here's a complete example that sets up internationalization based on browser settings:

import {
GemKit,
SdkSettings,
Language,
MapLanguage,
UnitSystem,
ISOCodeConversions,
ISOCodeType
} from '@magiclane/maps-sdk';

async function setupInternationalization() {
// 1. Set SDK language based on browser
const browserLang = navigator.language.split('-')[0]; // "en"
const langMap: { [key: string]: string } = {
'en': 'eng', 'fr': 'fra', 'de': 'deu', 'es': 'spa',
'it': 'ita', 'pt': 'por', 'ru': 'rus', 'zh': 'zho',
'ja': 'jpn', 'ko': 'kor', 'ar': 'ara', 'hi': 'hin'
};

const iso639_3 = langMap[browserLang] || 'eng';
const sdkLang = SdkSettings.getBestLanguageMatch(iso639_3);
if (sdkLang) {
SdkSettings.language = sdkLang;
}

// 2. Set map language
SdkSettings.mapLanguage = MapLanguage.automatic;

// 3. Set unit system based on browser locale
const locale = navigator.language;
const country = locale.split('-')[1] || '';

if (['US', 'AS', 'GU', 'MP', 'PR', 'VI'].includes(country)) {
SdkSettings.unitSystem = UnitSystem.imperialUS;
} else if (['GB', 'IE'].includes(country)) {
SdkSettings.unitSystem = UnitSystem.imperialUK;
} else {
SdkSettings.unitSystem = UnitSystem.metric;
}

// 4. Set number format based on browser locale
const testNumber = 1234.56;
const formatted = testNumber.toLocaleString(navigator.language);

if (formatted.includes(',') && formatted.indexOf(',') > formatted.indexOf('.')) {
SdkSettings.digitGroupSeparator = ',';
SdkSettings.decimalSeparator = '.';
} else if (formatted.includes('.') && formatted.indexOf('.') < formatted.lastIndexOf(',')) {
SdkSettings.digitGroupSeparator = '.';
SdkSettings.decimalSeparator = ',';
} else if (formatted.includes(' ')) {
SdkSettings.digitGroupSeparator = ' ';
SdkSettings.decimalSeparator = ',';
}

console.log('Internationalization setup complete:', {
language: SdkSettings.language?.name,
mapLanguage: SdkSettings.mapLanguage,
unitSystem: SdkSettings.unitSystem,
decimalSeparator: SdkSettings.decimalSeparator,
digitGroupSeparator: SdkSettings.digitGroupSeparator
});
}

// Initialize SDK and setup internationalization
window.addEventListener('DOMContentLoaded', async () => {
await GemKit.initialize('your-api-token');
await setupInternationalization();
});

User Language Preference

Allow users to manually override browser settings:

function createLanguageSelector() {
const languages = SdkSettings.languageList;
const select = document.createElement('select');

languages.forEach(lang => {
const option = document.createElement('option');
option.value = lang.languageCode;
option.textContent = lang.name;
if (lang.languageCode === SdkSettings.language?.languageCode) {
option.selected = true;
}
select.appendChild(option);
});

select.addEventListener('change', (e) => {
const selectedCode = (e.target as HTMLSelectElement).value;
const selectedLang = SdkSettings.getBestLanguageMatch(selectedCode);
if (selectedLang) {
SdkSettings.language = selectedLang;
console.log('Language changed to:', selectedLang.name);
}
});

return select;
}

// Add to your UI
const languageSelector = createLanguageSelector();
document.getElementById('settings-panel')?.appendChild(languageSelector);

Best Practices

  1. Detect browser language on initialization: Set SDK language based on navigator.language for better UX
  2. Provide language selector: Allow users to override automatic detection
  3. Sync unit systems: Match browser locale for units (metric vs imperial)
  4. Format numbers correctly: Use browser locale for decimal and group separators
  5. Handle missing translations: Provide fallbacks for unsupported languages
  6. Test with different locales: Verify behavior across various language and region combinations