diff --git a/.github/workflows/translator.yml b/.github/workflows/translator.yml deleted file mode 100644 index bad0c8b337..0000000000 --- a/.github/workflows/translator.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Translation Workflow - -on: - push: - branches: [main] - -jobs: - translate: - runs-on: ubuntu-latest - # Skip this workflow if the commit message contains "AUTOMATED TRANSLATIONS" - if: ${{ !contains(github.event.head_commit.message, 'AUTOMATED TRANSLATIONS') }} - - services: - libretranslate: - image: libretranslate/libretranslate:v1.3.11 - ports: - - 9999:5000 - env: - LT_DISABLE_FILES_TRANSLATION: "true" - LT_DISABLE_WEB_UI: "true" - LT_LOAD_ONLY: "en,es" - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Setup - uses: ./.github/actions/setup-all - - - name: Wait for LibreTranslate to be ready - run: | - for i in {1..60}; do - if curl -s -f http://localhost:9999/languages > /dev/null 2>&1; then - break - fi - if [ $i -eq 60 ]; then - echo "LibreTranslate failed to start" - exit 1 - fi - sleep 10 - done - - - name: Run translation tasks - run: mix gettext.translate - - - name: Commit and push - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config user.name "github-actions" - git config user.email "github-actions@github.com" - git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} - git add priv/gettext - git commit -m "AUTOMATED TRANSLATIONS" || echo "No changes to commit" - git push origin HEAD:${{ github.ref }} diff --git a/README.md b/README.md index 39901131df..27fe6aa87a 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,55 @@ Then, start the server with `iex -S mix phx.server` Then, visit the site at http://localhost:4001. +## How to support translations + +### Internationalizing strings in the application + +User-facing interfaces in Dotcom are internationalized, supporting 6 key languages. + +This is done via [the `Gettext` Elixir library](https://hex.pm/packages/gettext), which uses +[the GNU `gettext` tool](https://www.gnu.org/software/gettext) under the hood, +[managing `.po` files for message strings](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html). + +To internationalize a string in an interface, do the following: + +- Wrap strings to be translated in the `gettext` function, i.e. `gettext("your string here")`. + Note that you may need to wrap the function call in `{...}` for attribute strings. + +#### Rules Of Gettext + +1. No newlines inside a gettext call. Newlines are a new gettext call. +2. Don't start or end with whitespace. If you break a sentence up, leave the whitespace in the HTML untranslated. +3. If you break apart a sentence across multiple gettext calls, use `pgettext` and add context including the full sentence to help translators. Grep the app for `pgettext` for examples. + +Note that new strings will default to English language until translations are provided for them. + +### Preparing for Translations + +We use Smartling as our department approved vendor to complete translations - this is done through GitHub integrations. + +Smartling GitHub integration tracks main to see if changes are made to the translation files in PRs developers open. If this does happen, Smartling opens up seperate PRs to introduce the translated content for all of our supported languages to merge into the PR developers open. + +Here is the workflow for making updates to copy in Dotcom and completing translations: + 1. Make your changes in a branch (note that content branches should NOT begin with "smartling.") Localize the content in Dotcom using `gettext` as described in the above section. + 2. Run `mix localize` to update the `gettext` translation files. + * If this isn't run - we have a CI check to fail the build if the translation files are out of date, so there will be no + way to merge in changes without updated translations. + 3. Put up the changes in your branch to a PR. You will notice a `Not ready for translation` label automatically gets applied to your PR. **When your PR is reviewed and approved (but before it is merged), remove the label.** + 3. After some time, a Smartling machine translation PR will be opened, merging the translated content into your PR. + 4. Review the Smartling PR, approve, and merge it into your PR. The translated content will now be available in your PR. + 5. Get your updated feature PR merged into main. + +### How to review Smartling PRs +What's good to check for in review: +* Making sure nothing is glaringly wrong or off + * Do the files have translations (as opposed to empty strings etc.)? + * Glance over the file and make sure its structure looks reasonable +* Ensuring nothing is broken feature-wise/UX-wise + +What you _don't_ need to worry about: +* Reviewing the translations themselves for correctness + ## Algolia [Algolia](https://www.algolia.com) powers our search features. Sometimes after content updates or GTFS releases we will find that the search results do not contain up-to-date results. When this happens you can re-index the Algolia data by running: `mix algolia.update`. diff --git a/config/config.exs b/config/config.exs index f0afdf201a..9a05cec5a6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -18,7 +18,7 @@ config :dotcom, :httpoison, HTTPoison config :dotcom, default_locale_code: "en", - locale_codes: ["en", "es", "ht", "pt", "vi", "zh"] + locale_codes: ["en", "es", "ht", "pt-BR", "vi", "zh-CN", "zh-TW", "fr-FR"] config :dotcom, :location_service, LocationService diff --git a/lib/dotcom/gettext/plural.ex b/lib/dotcom/gettext/plural.ex index c3e701c51e..7d2c1f8220 100644 --- a/lib/dotcom/gettext/plural.ex +++ b/lib/dotcom/gettext/plural.ex @@ -1,5 +1,33 @@ defmodule Dotcom.Gettext.Plural do - @moduledoc false + @moduledoc """ + This module defines plural form equations for languages for PO files. - use Cldr.Gettext.Plural, cldr_backend: Dotcom.Cldr + Plural forms are documented in the gettext docs here: + https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms + + There's a list of plural forms for most languages here: + https://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html + """ + @behaviour Gettext.Plural + + # Haitian Creole is not supported by default by Gettext.Plural (which uses Expo.PluralForms) + def nplurals("ht"), do: 2 + + # Gettext.Plural forwards xx_YY to xx for plurals, but not xx-YY, so this patches that + def nplurals(<> <> "-" <> _sublocale), + do: Gettext.Plural.nplurals(locale) + + # Fall back to Gettext.Plural + defdelegate nplurals(locale), to: Gettext.Plural + + # Haitian Creole is not supported by default by Gettext.Plural (which uses Expo.PluralForms) + def plural("ht", 1), do: 0 + def plural("ht", _), do: 1 + + # Gettext.Plural forwards xx_YY to xx for plurals, but not xx-YY, so this patches that + def plural(<> <> "-" <> _sublocale, count), + do: Gettext.Plural.plural(locale, count) + + # Fall back to Gettext.Plural + defdelegate plural(locale, n), to: Gettext.Plural end diff --git a/lib/dotcom/locales.ex b/lib/dotcom/locales.ex index f86d2998e0..7aedd5e794 100644 --- a/lib/dotcom/locales.ex +++ b/lib/dotcom/locales.ex @@ -8,7 +8,7 @@ defmodule Dotcom.Locales do @default_locale %Locale{code: "en", endonym: "English"} @development_locale %Locale{code: "es", endonym: "Español"} - @development_additional_locales [ + @locales [ @default_locale, @development_locale, %Locale{code: "ht", endonym: "Kreyòl Ayisyen (Haitian Creole)"}, @@ -19,21 +19,6 @@ defmodule Dotcom.Locales do %Locale{code: "fr-FR", endonym: "Français (French)"} ] - def development_additional_locales do - @development_additional_locales - end - - # @future_locales [ - # %Locale{code: "ht", endonym: "Kreyòl Ayisyen"}, - # %Locale{code: "pt", endonym: "Português"}, - # %Locale{code: "vi", endonym: "Tiếng Việt"}, - # %Locale{code: "zh", endonym: "中文"} - # ] - @locales [ - @default_locale, - @development_locale - ] - @doc """ The default locale. """ diff --git a/lib/dotcom_web/templates/layout/_footer.html.heex b/lib/dotcom_web/templates/layout/_footer.html.heex index 1b42702d4f..6ba7066e0a 100644 --- a/lib/dotcom_web/templates/layout/_footer.html.heex +++ b/lib/dotcom_web/templates/layout/_footer.html.heex @@ -105,7 +105,7 @@