Skip to content

Bringing translations to the next level. #273

Closed
@machour

Description

@machour

Dears,

As mentionned in a previous issue, and on gitter, I think that the current system used for handling translations is flawed.

Here are the major problems I've seen/I predict:

  • keywords doesn't often make a lot of sense (had to check the source code to guess the context/meaning of some of them)
  • contributing becomes "harder". I'm introducing a new feature with some sentences, I have to check : If these sentences exists as keywords somewhere. If not, where should I put them ? under what namespaces ?
  • even reading the code source gets tedious: https://github.com/gitpoint/git-point/blob/master/src/auth/screens/events.screen.js#L491-L502
  • concatenation is bad: user + ' made ' + repository + 'public', is perfect for English, but it may not be suited for another language. Let's not speak about the mess it will be when we introduce a first RTL language
  • keeping translations up to date is tedious, as if someone changes the english value of the key, there's a big chance it will be missed by translators : c5b90da
  • currently, adding a entry en.js break all other languages. Contributors are using Google Translate in order to avoid this: feat(starred-count): show starred count #271 (comment)
  • last but not least, making sure that all translations are up to date before pushing next release to App stores is impossible for @housseindjirdeh and will require him to wait for all translators to respond.

In the past days, and with the help of @Antoine38660 (<3 buddy) I worked on a proof of concept for a better translation system, designed to solve all these problems and make contributors lifes easier.

Its concept is clearly inspired a lot by a PHP framework called Yii, which handles i18n in a clever way. [1]

The POC is available here: https://github.com/machour/rn-i18n-poc

(please keep in mind, I only did jQuery in the past and discovered const, import, yarn, let, export a week ago. Antoine did its best to enhance stuff, but I kept on breaking things.)

Here are the main features of this poorly coded idea :

Coding your app

  • The application is developed using english sentences, surrounded by a function, and using placeholders to inject values :
t("{user} made {repository} public", { 
	user: "Houssein",
	repository: "gitpoint/git-point"
});
  • Injected values can be strings, or ... React Components !

    t("{user} made {repository} public", { 
      user: "Houssein",
      repository: (<Button title="gitpoint/gitpoint" onPress={()=>console.log("you clicked")}>gitpoint/git-point</Button>)
    })
    
  • Pluralization handling :

t("There {n,plural,=0{are no cats} =1{is one cat} =*{are # cats}}!" {
 n: 0
}) // There are no cats!

t("There {n,plural,=0{are no cats} =1{is one cat} =*{are # cats}}!", {
 n: 1
}) // There is one cat!

t("There {n,plural,=0{are no cats} =1{is one cat} =*{are # cats}}!", {
 n: 42
}) // There are 42 cats!

You can see more features by running the app from the repo.

Actual translations

A string extraction script is provided and takes the following parameters :

  • sourcePath: The directory to be scanned for strings
  • translator: The function used in your app to trigger translations (t in the above examples)
  • languages: A comma separated list of languages code
  • messagePath: The directory where the messages files will be generated

The script produces a JS file with this structure (fr.js for example)

export default {
  "I think that {user} made {repository} public": "Je crois que {user} a rendu {repository} public",
  "This string is not translated and will automatically fallback to {language}": "",
  "This string should not trigger placeholders processing": "Cette phrase ne doit pas invoquer le processing des remplacements",
  "This string uses {nested}": "Cette phrase utilises des {nested}",
  "nested translating!": "traductions imbriquées :)",
  "Oops, I forgot to pass my {placeholder}": "Oups, j'ai oublié de passer mon {placeholder}",
  "A simple sentence without placeholders": "Une phrase simple sans motifs de remplacements",
  "Two {consecutive} {placeholders}": "Deux {placeholders} {consecutive}",
  "consecutive": "consecutifs",
  "placeholders": "motifs de remplacements",
  "A sentence {0} using {1} numerical {0} placeholders": "Une phrase {0} utilisant {1} des motifs {0} numériques",
  "A simple sentence with only one placeholder passed as a {0} without wrapping it in an array": "Une phrase simple avec un seul motif de remplacement passé en tant que {0} sans avoir à en faire un tableau",
  "There {n,plural,=0{are no cats} =1{is one cat} =*{are # cats}}!": "Il y a {n,plural,=0{aucun chat} =1{un chat} =*{# chats}}!",
  "Hello {name}. This is a component using t()": "Bonjour {name}. Ceci est un composant utilisant t()"
};
  • Any string not translated ( = "" ) will fallback to english (or the native language used to develop the app)
  • The script takes care of merging new extracted sentences with previously translated ones
  • If a sentence is removed from the application, it will be surrounded with @ symbols to hint the translator.

An additional script could be developed to make sure that all translations are up-to-date :

  1. run the extraction process
  2. iterate on generated files to test : if there are missing translations (empty) or obsolete ones (@ some old string@)

Having a running POC to show, and not so many skills, I decided to stop here, show you what I've been rambling about lately and have a first round of comments (or applauses 😆 ).

Could that be the next great way of handling translations in a React Native app ? (and I know, it could be made into a framework agnostic base, with several implementations).

Comments please.

[1] - If you want to see where I stoleborrowed the concept : http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions