Skip to content

Resolve "ENG: Localization Language Selector"

Closes #49 (closed)

Step 1: What is changing in this MR?

Language selector for BE and WWW with full features implemented to solve the questions below:

How can we detect when localization is available for a page?

The solution implemented to detect if a page has localization pages available in order to show them in the language selector or not to show the language selector at all was to validate if the localization URL's exist validating each of them by checking the 404 status. This approach works with pages that are built with i18n or with Smartling.

  1. Method that validates if a URL exists, it was placed in a new file called utils.ts
export const checkIfUrlExists = (url: string) => {
  return new Promise((resolve, reject) => {
    fetch(url)
      .then((response) => resolve(response.status !== 404))
      .catch((error) => reject(error));
  });
};
  1. Method that validates the current page by calling the URL checker with each of the language paths that are supported in the application. Depending on which URL's exist or not, an array of availableLanguages is returned. It works with prefix and non-prefix pages (i.e /sales, /de-de/sales)
export const getPageAvailableLanguages = async (
  baseUrl: string,
  path: string
): Promise<any[]> => {
  const currentLanguage = LANG_OPTIONS.find(
    (language) => language.path !== "" && path.includes(language.path)
  );

  const localizationPromises = LANG_OPTIONS.map((language) => {
    let url = `${baseUrl}${language.path}${path}`;

    if (currentLanguage) {
      url = url.replace(currentLanguage.path, "");
    }

    return checkIfUrlExists(url);
  });

  const response = await Promise.all(localizationPromises);

  // The Promise.all method strictly keeps the same order, allowing the use of response[index]
  const availableLanguages = LANG_OPTIONS.filter((_, index) => response[index]);

  return availableLanguages;
};
  1. The final step is to execute the getPageAvailableLanguages in the language selector to show the available languages or not show the selector at all.

What functionality does the language selector provide the user?

The Language Selector feature enables users to select their preferred language, which will be saved in the LocalStorage for future visits. Upon selecting a language, the user will be automatically redirected to the localized version of the website or application. This feature streamlines the user experience by allowing them to seamlessly switch between languages without having to manually navigate to the correct version of the site or application.

  1. First of all, the availableLanguages is fetched using the process explained earlier, if the availableLanguages array is empty or only has the default language, the language selector won't be shown in the navigation. The navigation will be hidden depending on the computed property called showSelector:
computed: {
    showSelector(): boolean {
      return this.availableLanguages.length > 1;
    },
},
  1. Before the component is mounted, the user's preferred language is validated in order to know which page to show the user and what language to show as selected in the UI. In order to achieve this, the localStorage is validated, if it's empty, the navigator.language is compared with the available languages to check if the browser's language can be used as the selected language. If neither of those validations detects the user's language, the default(English) language will be set and also persisted in the localStorage. Note: It's important to keep populated the lang in the local storage for the Localized Navigation to work correctly.
determineUserPreferredLanguage() {
      const flatLang = localStorage.getItem("lang");
      let selectedLang;

      if (flatLang) {
        selectedLang = JSON.parse(flatLang);
      } else if (this.showSelector) {
        selectedLang = this.availableLanguages.find(
          (language) => navigator.language === language.value
        );
      }

      selectedLang = selectedLang
        ? selectedLang
        : this.langOptions.find((lang) => lang.default);

      this.onSelectLanguage(selectedLang);
},
  1. The onSelectLanguage method is responsible for persisting the user's language preference in the localStorage after it has been validated. This method is also called whenever the user selects a new language from the language selector. In addition to saving the language preference, the method also triggers the switchLocalePath method, which redirects the user to the corresponding localized version of the website or application.
onSelectLanguage(language: Language) {
   this.selectedLang = language;
   localStorage.setItem("lang", JSON.stringify(this.selectedLang));
   this.switchLocalePath();
},
switchLocalePath() {
   const path = window.location.pathname;
   const unLocalizedPath = getUnlocalizedPath(path);
   const newPath = `${this.selectedLang?.path}${unLocalizedPath}`;

   if (path !== newPath) {
      window.location.href = `${window.location.origin}${newPath}`;
   }
},

What happens when a user navigates from a localized page to a un-localized page & how does this effect the language selector?

When a user moves from a localized page to an un-localized page, the language selector won't be displayed because the available language options are limited to just one page.

On the other hand, when a user navigates from an un-localized page to a localized one, the language selector will access the user's preferred language from their local storage and redirect them to the corresponding localized page. This ensures that the user sees the content in their preferred language without having to manually select it.

How will the language selector work when pulled into Buyer Experience repository via the navigation NPM package?

A test MR has been created in order to test the functionality as it is not possible to test in the Navigation repository.

Test MR and Review App

How will the language selector work when pulled into www-gitlab-com repository via the navigation NPM package?

Unfortunately, the www-gitlab-com project lacks localization domains in its review apps, which makes it extremely difficult to test this feature in a non-production environment. This is because Smartling, the localization tool used by the project, is only available in the production environment.

Step 2: Ensure that your changes comply with the following, where applicable:

  • I, the Assignee, have run Axe tools on any updated pages, and fixed the relevant accessibility issues.
  • These changes meet a specific OKR or item in our Quarterly Plan.
  • These changes work on both Safari, Chrome, and Firefox.
  • These changes have been reviewed for Visual Quality Assurance and Functional Quality Assurance on Mobile, Desktop, and Tablet.
  • These changes work with our Google Analytics and SEO tools.
  • These changes have been documented as expected.

Step 3: Add the appropriate labels for triage

This MR will have dex-approval::2-standard automatically applied, but please update it as follows. If deciding between two levels, go with the higher of the two:

  1. dex-approval::1-minor
    1. Example of the type of change: typos or content changes.
      1. Anyone on the Digital Experience team can approve and merge.
      2. Once approved by the Digital Experience team, the MR creator can merge.
    2. Example of the type of change: /customers filter is displaying the wrong results.
      1. Anyone on the Digital Experience team can approve and merge.
      2. Once approved by the Digital Experience team, the MR creator can merge.
  2. dex-approval::2-standard
    1. Example of the type of change: re-arranging components on a page.
      1. Once the Digital Experience team approves, members of the Digital Experience team can merge.
      2. Members of the Digital Experience team should keep their Managers informed.
      3. Manager’s discretion to align with the Director of Digital Experience or not.
    2. Example of the type of change: Adding new pages.
      1. Managers of Digital Experience can approve and merge.
      2. Manager should align with Director, Digital Experience.
  3. dex-approval::3-key-page
    1. Example of the type of change: Changing Nav
      1. Directors and Managers of Digital Experience need to align.
      2. Managers of Digital Experience can approve and merge.
    2. Example of the type of change: Changes to key drivers of traffic and/or business goals etc. (Homepage, Pricing Page, Why GitLab).
      1. Director, Digital Experience can approve and merge.
      2. Director, Digital Experience will keep Marketing leadership informed of all Major Changes.
  4. dex-approval::4-legal
    1. Example of the type of change: Any changes to company information, board/director information, etc.
      1. Legal and Director of Digital Experience must approve.
    2. Example of the type of change: Changes to sign-up workflows or alteration/omission of footers/links to anything legal-related.
      1. Legal and Director of Digital Experience must approve.

Step 4: Tag the appropriate person for review

Depending on which label is used, you may tag the following people as a Reviewer on this MR:

  1. Level 1: Any member of the Digital Experience Team
  2. Level 2: Any member of the Digital Experience team
  3. Level 3: Ping @gitlab-com/marketing/digital-experience in a comment. This will tag the Digital Experience Leadership team, and they can review. When in doubt, tag @mpreuss as a reviewer.
  4. Level 4: This will need Legal approval. Tag @mpreuss and he can loop in the legal team.
Edited by Lauren Barker

Merge request reports